OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
HdaCodec.c
Go to the documentation of this file.
1/*
2 * File: HdaCodec.c
3 *
4 * Copyright (c) 2018 John Davis
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include "HdaCodec.h"
27
28#include <Library/BaseOverflowLib.h>
30#include <Library/OcMiscLib.h>
31#include <Library/OcStringLib.h>
32
33UINTN
35
36UINTN
38
39UINTN
41
42BOOLEAN
44
45UINTN
47
48BOOLEAN
50
51EFI_STATUS
52EFIAPI
54 IN HDA_WIDGET_DEV *HdaWidget
55 )
56{
57 EFI_STATUS Status;
59 UINT8 Index;
60 UINT16 ConnIndex;
61
62 UINT32 Response;
63 UINT8 ConnectionListThresh;
64 UINT32 AmpInCount;
65 UINT8 ActualConnectionCount;
66 UINT16 Connection;
67 UINT16 ConnectionPrev;
68 UINT16 ConnectionValue;
69 UINT16 ConnectionPrevValue;
70 BOOLEAN IsRangedEntry;
71
72 HdaIo = HdaWidget->FuncGroup->HdaCodecDev->HdaIo;
73 Response = 0;
74
75 //
76 // Get widget capabilities.
77 //
78 Status = HdaIo->SendCommand (
79 HdaIo,
80 HdaWidget->NodeId,
82 &HdaWidget->Capabilities
83 );
84 if (EFI_ERROR (Status)) {
85 return Status;
86 }
87
88 HdaWidget->Type = HDA_PARAMETER_WIDGET_CAPS_TYPE (HdaWidget->Capabilities);
89 HdaWidget->AmpOverride = HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_AMP_OVERRIDE;
90 // DEBUG((DEBUG_INFO, "Widget @ 0x%X type: 0x%X\n", HdaWidget->NodeId, HdaWidget->Type));
91 // DEBUG((DEBUG_INFO, "Widget @ 0x%X capabilities: 0x%X\n", HdaWidget->NodeId, HdaWidget->Capabilities));
92
93 //
94 // Get default unsolicitation.
95 //
96 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_UNSOL_CAPABLE) {
97 Status = HdaIo->SendCommand (
98 HdaIo,
99 HdaWidget->NodeId,
101 &Response
102 );
103 if (EFI_ERROR (Status)) {
104 return Status;
105 }
106
107 HdaWidget->DefaultUnSol = (UINT8)Response;
108 // DEBUG((DEBUG_INFO, "Widget @ 0x%X unsolicitation: 0x%X\n", HdaWidget->NodeId, HdaWidget->DefaultUnSol));
109 }
110
111 //
112 // Get connections.
113 //
114 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_CONN_LIST) {
115 Status = HdaIo->SendCommand (
116 HdaIo,
117 HdaWidget->NodeId,
119 &HdaWidget->ConnectionListLength
120 );
121 if (EFI_ERROR (Status)) {
122 return Status;
123 }
124
125 ActualConnectionCount = HDA_PARAMETER_CONN_LIST_LENGTH_LEN (HdaWidget->ConnectionListLength);
126 // DEBUG((DEBUG_INFO, "Widget @ 0x%X connection list length: 0x%X\n", HdaWidget->NodeId, HdaWidget->ConnectionListLength));
127
128 HdaWidget->ConnectionCount = ActualConnectionCount;
129
130 //
131 // Some connection entries may have ranges, we'll need to probe connections first to ensure an accurate count.
132 //
133 ConnectionListThresh = (HdaWidget->ConnectionListLength & HDA_PARAMETER_CONN_LIST_LENGTH_LONG) ? 2 : 4;
134 Connection = 0;
135 ConnectionValue = 0;
136 for (Index = 0; Index < ActualConnectionCount; Index++) {
137 //
138 // Entries are pulled in multiples of 2 or 4 depending on entry length.
139 //
140 if (Index % ConnectionListThresh == 0) {
141 Status = HdaIo->SendCommand (
142 HdaIo,
143 HdaWidget->NodeId,
145 &Response
146 );
147 if (EFI_ERROR (Status)) {
148 return Status;
149 }
150 }
151
152 ConnectionPrev = Connection;
153 ConnectionPrevValue = ConnectionValue;
154
155 if (HdaWidget->ConnectionListLength & HDA_PARAMETER_CONN_LIST_LENGTH_LONG) {
156 Connection = HDA_VERB_GET_CONN_LIST_ENTRY_LONG (Response, Index % 2);
157 IsRangedEntry = Index > 0
158 && (ConnectionPrev & HDA_VERB_GET_CONN_LIST_ENTRY_LONG_IS_RANGE) == 0
160 ConnectionValue = HDA_VERB_GET_CONN_LIST_ENTRY_LONG_VALUE (Connection);
161 } else {
162 Connection = HDA_VERB_GET_CONN_LIST_ENTRY_SHORT (Response, Index % 4);
163 IsRangedEntry = Index > 0
164 && (ConnectionPrev & HDA_VERB_GET_CONN_LIST_ENTRY_SHORT_IS_RANGE) == 0
166 ConnectionValue = HDA_VERB_GET_CONN_LIST_ENTRY_SHORT_VALUE (Connection);
167 }
168
169 //
170 // Do we have a connection list range?
171 // The first entry cannot be a range, nor can there be two sequential entries marked as a range.
172 //
173 if (IsRangedEntry && (ConnectionValue > ConnectionPrevValue)) {
174 if (BaseOverflowAddU32 (HdaWidget->ConnectionCount, ConnectionValue - ConnectionPrevValue, &HdaWidget->ConnectionCount)) {
175 return EFI_OUT_OF_RESOURCES;
176 }
177 }
178 }
179
180 HdaWidget->Connections = AllocateZeroPool (sizeof (UINT16) * HdaWidget->ConnectionCount);
181 if (HdaWidget->Connections == NULL) {
182 return EFI_OUT_OF_RESOURCES;
183 }
184
185 Connection = 0;
186 ConnectionValue = 0;
187 for (Index = 0, ConnIndex = 0; ConnIndex < ActualConnectionCount; ConnIndex++) {
188 //
189 // Entries are pulled in multiples of 2 or 4 depending on entry length.
190 //
191 if (Index % ConnectionListThresh == 0) {
192 Status = HdaIo->SendCommand (
193 HdaIo,
194 HdaWidget->NodeId,
196 &Response
197 );
198 if (EFI_ERROR (Status)) {
199 return Status;
200 }
201 }
202
203 ConnectionPrev = Connection;
204 ConnectionPrevValue = ConnectionValue;
205
206 if (HdaWidget->ConnectionListLength & HDA_PARAMETER_CONN_LIST_LENGTH_LONG) {
207 Connection = HDA_VERB_GET_CONN_LIST_ENTRY_LONG (Response, ConnIndex % 2);
208 IsRangedEntry = ConnIndex > 0
209 && (ConnectionPrev & HDA_VERB_GET_CONN_LIST_ENTRY_LONG_IS_RANGE) == 0
211 ConnectionValue = HDA_VERB_GET_CONN_LIST_ENTRY_LONG_VALUE (Connection);
212 } else {
213 Connection = HDA_VERB_GET_CONN_LIST_ENTRY_SHORT (Response, ConnIndex % 4);
214 IsRangedEntry = ConnIndex > 0
215 && (ConnectionPrev & HDA_VERB_GET_CONN_LIST_ENTRY_SHORT_IS_RANGE) == 0
217 ConnectionValue = HDA_VERB_GET_CONN_LIST_ENTRY_SHORT_VALUE (Connection);
218 }
219
220 //
221 // Do we have a connection list range?
222 // The first entry cannot be a range, nor can there be two sequential entries marked as a range.
223 //
224 if (IsRangedEntry && (ConnectionValue > ConnectionPrevValue)) {
225 while (ConnectionValue > ConnectionPrevValue) {
226 ConnectionPrevValue++;
227 HdaWidget->Connections[Index] = ConnectionPrevValue;
228 Index++;
229 }
230 } else {
231 HdaWidget->Connections[Index] = ConnectionValue;
232 }
233
234 Index++;
235 }
236 }
237
238 // Print connections.
239 // DEBUG((DEBUG_INFO, "Widget @ 0x%X connections (%u):", HdaWidget->NodeId, HdaWidget->ConnectionCount));
240 // for (UINT8 c = 0; c < HdaWidget->ConnectionCount; c++)
241 // DEBUG((DEBUG_INFO, " 0x%X", HdaWidget->Connections[c]));
242 // DEBUG((DEBUG_INFO, "\n"));
243
244 // Does the widget support power management?
245 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_POWER_CNTRL) {
246 // Get supported power states.
247 Status = HdaIo->SendCommand (
248 HdaIo,
249 HdaWidget->NodeId,
251 &HdaWidget->SupportedPowerStates
252 );
253 if (EFI_ERROR (Status)) {
254 return Status;
255 }
256
257 // DEBUG((DEBUG_INFO, "Widget @ 0x%X supported power states: 0x%X\n", HdaWidget->NodeId, HdaWidget->SupportedPowerStates));
258
259 // Get default power state.
260 Status = HdaIo->SendCommand (
261 HdaIo,
262 HdaWidget->NodeId,
264 &HdaWidget->DefaultPowerState
265 );
266 if (EFI_ERROR (Status)) {
267 return Status;
268 }
269
270 // DEBUG((DEBUG_INFO, "Widget @ 0x%X power state: 0x%X\n", HdaWidget->NodeId, HdaWidget->DefaultPowerState));
271 }
272
273 // Do we have input amps?
274 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_IN_AMP) {
275 // Get input amp capabilities.
276 Status = HdaIo->SendCommand (
277 HdaIo,
278 HdaWidget->NodeId,
280 &HdaWidget->AmpInCapabilities
281 );
282 if (EFI_ERROR (Status)) {
283 return Status;
284 }
285
286 // DEBUG((DEBUG_INFO, "Widget @ 0x%X input amp capabilities: 0x%X\n", HdaWidget->NodeId, HdaWidget->AmpInCapabilities));
287
288 // Determine number of input amps and allocate arrays.
289 AmpInCount = HdaWidget->ConnectionCount;
290 if (AmpInCount < 1) {
291 AmpInCount = 1;
292 }
293
294 HdaWidget->AmpInLeftDefaultGainMute = AllocateZeroPool (sizeof (UINT8) * AmpInCount);
295 if (HdaWidget->AmpInLeftDefaultGainMute == NULL) {
296 return EFI_OUT_OF_RESOURCES;
297 }
298
299 HdaWidget->AmpInRightDefaultGainMute = AllocateZeroPool (sizeof (UINT8) * AmpInCount);
300 if (HdaWidget->AmpInRightDefaultGainMute == NULL) {
301 FreePool (HdaWidget->AmpInLeftDefaultGainMute);
302 return EFI_OUT_OF_RESOURCES;
303 }
304
305 // Get default gain/mute for input amps.
306 for (UINT8 i = 0; i < AmpInCount; i++) {
307 // Get left.
308 Status = HdaIo->SendCommand (
309 HdaIo,
310 HdaWidget->NodeId,
314 ),
315 &Response
316 );
317 if (EFI_ERROR (Status)) {
318 return Status;
319 }
320
321 HdaWidget->AmpInLeftDefaultGainMute[i] = (UINT8)Response;
322
323 // Get right.
324 Status = HdaIo->SendCommand (
325 HdaIo,
326 HdaWidget->NodeId,
329 HDA_VERB_GET_AMP_GAIN_MUTE_PAYLOAD (i, FALSE, FALSE)
330 ),
331 &Response
332 );
333 if (EFI_ERROR (Status)) {
334 return Status;
335 }
336
337 HdaWidget->AmpInRightDefaultGainMute[i] = (UINT8)Response;
338 // DEBUG((DEBUG_INFO, "Widget @ 0x%X input amp %u defaults: 0x%X 0x%X\n", HdaWidget->NodeId, i,
339 // HdaWidget->AmpInLeftDefaultGainMute[i], HdaWidget->AmpInRightDefaultGainMute[i]));
340 }
341 }
342
343 // Do we have an output amp?
344 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_OUT_AMP) {
345 // Get output amp capabilities.
346 Status = HdaIo->SendCommand (
347 HdaIo,
348 HdaWidget->NodeId,
350 &HdaWidget->AmpOutCapabilities
351 );
352 if (EFI_ERROR (Status)) {
353 return Status;
354 }
355
356 DEBUG ((DEBUG_INFO, "HDA: | Widget @ 0x%X output amp capabilities: 0x%X\n", HdaWidget->NodeId, HdaWidget->AmpOutCapabilities));
357
358 // Get left.
359 Status = HdaIo->SendCommand (
360 HdaIo,
361 HdaWidget->NodeId,
365 ),
366 &Response
367 );
368 if (EFI_ERROR (Status)) {
369 return Status;
370 }
371
372 HdaWidget->AmpOutLeftDefaultGainMute = (UINT8)Response;
373
374 // Get right.
375 Status = HdaIo->SendCommand (
376 HdaIo,
377 HdaWidget->NodeId,
381 ),
382 &Response
383 );
384 if (EFI_ERROR (Status)) {
385 return Status;
386 }
387
388 HdaWidget->AmpOutRightDefaultGainMute = (UINT8)Response;
389 // DEBUG((DEBUG_INFO, "Widget @ 0x%X output amp defaults: 0x%X 0x%X\n", HdaWidget->NodeId,
390 // HdaWidget->AmpOutLeftDefaultGainMute, HdaWidget->AmpOutRightDefaultGainMute));
391 }
392
393 // Is the widget an Input or Output?
394 if ((HdaWidget->Type == HDA_WIDGET_TYPE_INPUT) || (HdaWidget->Type == HDA_WIDGET_TYPE_OUTPUT)) {
395 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_FORMAT_OVERRIDE) {
396 // Get supported PCM sizes/rates.
397 Status = HdaIo->SendCommand (
398 HdaIo,
399 HdaWidget->NodeId,
401 &HdaWidget->SupportedPcmRates
402 );
403 if (EFI_ERROR (Status)) {
404 return Status;
405 }
406
407 // DEBUG((DEBUG_INFO, "Widget @ 0x%X supported PCM sizes/rates: 0x%X\n", HdaWidget->NodeId, HdaWidget->SupportedPcmRates));
408
409 // Get supported stream formats.
410 Status = HdaIo->SendCommand (
411 HdaIo,
412 HdaWidget->NodeId,
414 &HdaWidget->SupportedFormats
415 );
416 if (EFI_ERROR (Status)) {
417 return Status;
418 }
419
420 // DEBUG((DEBUG_INFO, "Widget @ 0x%X supported formats: 0x%X\n", HdaWidget->NodeId, HdaWidget->SupportedFormats));
421 }
422
423 // Get default converter format.
424 Status = HdaIo->SendCommand (
425 HdaIo,
426 HdaWidget->NodeId,
428 &Response
429 );
430 if (EFI_ERROR (Status)) {
431 return Status;
432 }
433
434 HdaWidget->DefaultConvFormat = (UINT16)Response;
435 // DEBUG((DEBUG_INFO, "Widget @ 0x%X default format: 0x%X\n", HdaWidget->NodeId, HdaWidget->DefaultConvFormat));
436
437 // Get default converter stream/channel.
438 Status = HdaIo->SendCommand (
439 HdaIo,
440 HdaWidget->NodeId,
442 &Response
443 );
444 if (EFI_ERROR (Status)) {
445 return Status;
446 }
447
448 HdaWidget->DefaultConvStreamChannel = (UINT8)Response;
449 // DEBUG((DEBUG_INFO, "Widget @ 0x%X default stream/channel: 0x%X\n", HdaWidget->NodeId, HdaWidget->DefaultConvStreamChannel));
450
451 // Get default converter channel count.
452 Status = HdaIo->SendCommand (
453 HdaIo,
454 HdaWidget->NodeId,
456 &Response
457 );
458 if (EFI_ERROR (Status)) {
459 return Status;
460 }
461
462 HdaWidget->DefaultConvChannelCount = (UINT8)Response;
463 // DEBUG((DEBUG_INFO, "Widget @ 0x%X default channel count: 0x%X\n", HdaWidget->NodeId, HdaWidget->DefaultConvChannelCount));
464 } else if (HdaWidget->Type == HDA_WIDGET_TYPE_PIN_COMPLEX) {
465 // Is the widget a Pin Complex?
466 // Get pin capabilities.
467 Status = HdaIo->SendCommand (
468 HdaIo,
469 HdaWidget->NodeId,
471 &HdaWidget->PinCapabilities
472 );
473 if (EFI_ERROR (Status)) {
474 return Status;
475 }
476
477 // DEBUG((DEBUG_INFO, "Widget @ 0x%X pin capabilities: 0x%X\n", HdaWidget->NodeId, HdaWidget->PinCapabilities));
478
479 // Get default EAPD.
480 if (HdaWidget->PinCapabilities & HDA_PARAMETER_PIN_CAPS_EAPD) {
481 Status = HdaIo->SendCommand (
482 HdaIo,
483 HdaWidget->NodeId,
485 &Response
486 );
487 if (EFI_ERROR (Status)) {
488 return Status;
489 }
490
491 HdaWidget->DefaultEapd = (UINT8)Response;
492 HdaWidget->DefaultEapd &= 0x7;
493 HdaWidget->DefaultEapd |= HDA_EAPD_BTL_ENABLE_EAPD;
494 // DEBUG((DEBUG_INFO, "Widget @ 0x%X EAPD: 0x%X\n", HdaWidget->NodeId, HdaWidget->DefaultEapd));
495 }
496
497 // Get default pin control.
498 Status = HdaIo->SendCommand (
499 HdaIo,
500 HdaWidget->NodeId,
502 &Response
503 );
504 if (EFI_ERROR (Status)) {
505 return Status;
506 }
507
508 HdaWidget->DefaultPinControl = (UINT8)Response;
509 // DEBUG((DEBUG_INFO, "Widget @ 0x%X default pin control: 0x%X\n", HdaWidget->NodeId, HdaWidget->DefaultPinControl));
510
511 // Get default pin configuration.
512 Status = HdaIo->SendCommand (
513 HdaIo,
514 HdaWidget->NodeId,
516 &HdaWidget->DefaultConfiguration
517 );
518 if (EFI_ERROR (Status)) {
519 return Status;
520 }
521
522 // DEBUG((DEBUG_INFO, "Widget @ 0x%X default pin configuration: 0x%X\n", HdaWidget->NodeId, HdaWidget->DefaultConfiguration));
523 } else if (HdaWidget->Type == HDA_WIDGET_TYPE_VOLUME_KNOB) {
524 // Is the widget a Volume Knob?
525 // Get volume knob capabilities.
526 Status = HdaIo->SendCommand (
527 HdaIo,
528 HdaWidget->NodeId,
530 &HdaWidget->VolumeCapabilities
531 );
532 if (EFI_ERROR (Status)) {
533 return Status;
534 }
535
536 // DEBUG((DEBUG_INFO, "Widget @ 0x%X volume knob capabilities: 0x%X\n", HdaWidget->NodeId, HdaWidget->VolumeCapabilities));
537
538 // Get default volume.
539 Status = HdaIo->SendCommand (
540 HdaIo,
541 HdaWidget->NodeId,
543 &Response
544 );
545 if (EFI_ERROR (Status)) {
546 return Status;
547 }
548
549 HdaWidget->DefaultVolume = (UINT8)Response;
550 // DEBUG((DEBUG_INFO, "Widget @ 0x%X default volume: 0x%X\n", HdaWidget->NodeId, HdaWidget->DefaultVolume));
551 }
552
553 return EFI_SUCCESS;
554}
555
556EFI_STATUS
557EFIAPI
559 IN HDA_FUNC_GROUP *FuncGroup
560 )
561{
562 DEBUG ((DEBUG_VERBOSE, "HdaCodecProbeFuncGroup(): start\n"));
563
564 // Create variables.
565 EFI_STATUS Status;
566 EFI_HDA_IO_PROTOCOL *HdaIo = FuncGroup->HdaCodecDev->HdaIo;
567 UINT32 Response;
568
569 UINT8 WidgetStart;
570 UINT8 WidgetEnd;
571 UINT8 WidgetCount;
572 HDA_WIDGET_DEV *HdaWidget;
573 HDA_WIDGET_DEV *HdaConnectedWidget;
574
575 // Get function group type.
576 Status = HdaIo->SendCommand (
577 HdaIo,
578 FuncGroup->NodeId,
580 &Response
581 );
582 if (EFI_ERROR (Status)) {
583 return Status;
584 }
585
586 FuncGroup->Type = HDA_PARAMETER_FUNC_GROUP_TYPE_NODETYPE (Response);
587 FuncGroup->UnsolCapable = (Response & HDA_PARAMETER_FUNC_GROUP_TYPE_UNSOL) != 0;
588
589 // Determine if function group is an audio one. If not, we cannot support it.
590 DEBUG ((DEBUG_INFO, "HDA: | Function group @ 0x%X is of type 0x%X\n", FuncGroup->NodeId, FuncGroup->Type));
591 if (FuncGroup->Type != HDA_FUNC_GROUP_TYPE_AUDIO) {
592 return EFI_UNSUPPORTED;
593 }
594
595 // Get function group capabilities.
596 Status = HdaIo->SendCommand (
597 HdaIo,
598 FuncGroup->NodeId,
600 &FuncGroup->Capabilities
601 );
602 if (EFI_ERROR (Status)) {
603 return Status;
604 }
605
606 // DEBUG((DEBUG_INFO, "HDA: | Function group @ 0x%X capabilities: 0x%X\n", FuncGroup->NodeId, FuncGroup->Capabilities));
607
608 // Get default supported PCM sizes/rates.
609 Status = HdaIo->SendCommand (
610 HdaIo,
611 FuncGroup->NodeId,
613 &FuncGroup->SupportedPcmRates
614 );
615 if (EFI_ERROR (Status)) {
616 return Status;
617 }
618
619 // DEBUG((DEBUG_INFO, "HDA: | Function group @ 0x%X supported PCM sizes/rates: 0x%X\n", FuncGroup->NodeId, FuncGroup->SupportedPcmRates));
620
621 // Get default supported stream formats.
622 Status = HdaIo->SendCommand (
623 HdaIo,
624 FuncGroup->NodeId,
626 &FuncGroup->SupportedFormats
627 );
628 if (EFI_ERROR (Status)) {
629 return Status;
630 }
631
632 // DEBUG((DEBUG_INFO, "HDA: | Function group @ 0x%X supported formats: 0x%X\n", FuncGroup->NodeId, FuncGroup->SupportedFormats));
633
634 // Get default input amp capabilities.
635 Status = HdaIo->SendCommand (
636 HdaIo,
637 FuncGroup->NodeId,
639 &FuncGroup->AmpInCapabilities
640 );
641 if (EFI_ERROR (Status)) {
642 return Status;
643 }
644
645 // DEBUG((DEBUG_INFO, "HDA: | Function group @ 0x%X input amp capabilities: 0x%X\n", FuncGroup->NodeId, FuncGroup->AmpInCapabilities));
646
647 // Get default output amp capabilities.
648 Status = HdaIo->SendCommand (
649 HdaIo,
650 FuncGroup->NodeId,
652 &FuncGroup->AmpOutCapabilities
653 );
654 if (EFI_ERROR (Status)) {
655 return Status;
656 }
657
658 DEBUG ((DEBUG_INFO, "HDA: | Function group @ 0x%X output amp capabilities: 0x%X\n", FuncGroup->NodeId, FuncGroup->AmpOutCapabilities));
659
660 // Get supported power states.
661 Status = HdaIo->SendCommand (
662 HdaIo,
663 FuncGroup->NodeId,
665 &FuncGroup->SupportedPowerStates
666 );
667 if (EFI_ERROR (Status)) {
668 return Status;
669 }
670
671 // DEBUG((DEBUG_INFO, "HDA: | Function group @ 0x%X supported power states: 0x%X\n", FuncGroup->NodeId, FuncGroup->SupportedPowerStates));
672
673 // Get GPIO capabilities.
674 Status = HdaIo->SendCommand (
675 HdaIo,
676 FuncGroup->NodeId,
678 &FuncGroup->GpioCapabilities
679 );
680 if (EFI_ERROR (Status)) {
681 return Status;
682 }
683
684 DEBUG ((DEBUG_INFO, "HDA: | Function group @ 0x%X GPIO capabilities: 0x%X\n", FuncGroup->NodeId, FuncGroup->GpioCapabilities));
685
686 // Get number of widgets in function group.
687 Status = HdaIo->SendCommand (
688 HdaIo,
689 FuncGroup->NodeId,
691 &Response
692 );
693 if (EFI_ERROR (Status)) {
694 return Status;
695 }
696
697 WidgetStart = HDA_PARAMETER_SUBNODE_COUNT_START (Response);
698 WidgetCount = HDA_PARAMETER_SUBNODE_COUNT_TOTAL (Response);
699 WidgetEnd = WidgetStart + WidgetCount - 1;
700 DEBUG ((
701 DEBUG_INFO,
702 "HDA: | Function group @ 0x%X contains %u widgets, start @ 0x%X, end @ 0x%X\n",
703 FuncGroup->NodeId,
704 WidgetCount,
705 WidgetStart,
706 WidgetEnd
707 ));
708
709 // Power up.
710 Status = HdaIo->SendCommand (HdaIo, FuncGroup->NodeId, HDA_CODEC_VERB (HDA_VERB_SET_POWER_STATE, 0), &Response);
711 ASSERT_EFI_ERROR (Status);
712
713 // Ensure there are widgets.
714 if (WidgetCount == 0) {
715 return EFI_UNSUPPORTED;
716 }
717
718 // Allocate space for widgets.
719 FuncGroup->Widgets = AllocateZeroPool (sizeof (HDA_WIDGET_DEV) * WidgetCount);
720 if (FuncGroup->Widgets == NULL) {
721 return EFI_OUT_OF_RESOURCES;
722 }
723
724 FuncGroup->WidgetsCount = WidgetCount;
725
726 // Probe widgets.
727 DEBUG ((DEBUG_VERBOSE, "HdaCodecProbeFuncGroup(): probing widgets\n"));
728 for (UINT8 w = 0; w < WidgetCount; w++) {
729 // Get widget.
730 HdaWidget = FuncGroup->Widgets + w;
731
732 // Probe widget.
733 HdaWidget->FuncGroup = FuncGroup;
734 HdaWidget->NodeId = WidgetStart + w;
735 Status = HdaCodecProbeWidget (HdaWidget);
736 ASSERT_EFI_ERROR (Status);
737
738 // Power up.
740 Status = HdaIo->SendCommand (HdaIo, HdaWidget->NodeId, HDA_CODEC_VERB (HDA_VERB_SET_POWER_STATE, 0), &Response);
741 ASSERT_EFI_ERROR (Status);
742 }
743 }
744
745 // Probe widget connections.
746 DEBUG ((DEBUG_VERBOSE, "HdaCodecProbeFuncGroup(): probing widget connections\n"));
747 for (UINT8 w = 0; w < WidgetCount; w++) {
748 // Get widget.
749 HdaWidget = FuncGroup->Widgets + w;
750
751 // Get connections.
752 if (HdaWidget->ConnectionCount > 0) {
753 // Allocate array of widget pointers.
754 HdaWidget->WidgetConnections = AllocateZeroPool (sizeof (HDA_WIDGET_DEV *) * HdaWidget->ConnectionCount);
755 if (HdaWidget->WidgetConnections == NULL) {
756 return EFI_OUT_OF_RESOURCES;
757 }
758
759 // Populate array.
760 for (UINT8 c = 0; c < HdaWidget->ConnectionCount; c++) {
761 // Get widget index.
762 // This can be gotten using the node ID of the connection minus our starting node ID.
763 UINT16 WidgetIndex = HdaWidget->Connections[c] - WidgetStart;
764
765 // Save pointer to widget.
766 HdaConnectedWidget = FuncGroup->Widgets + WidgetIndex;
767 // DEBUG((DEBUG_INFO, "Widget @ 0x%X found connection to index %u (0x%X, type 0x%X)\n",
768 // HdaWidget->NodeId, WidgetIndex, HdaConnectedWidget->NodeId, HdaConnectedWidget->Type));
769 HdaWidget->WidgetConnections[c] = HdaConnectedWidget;
770 }
771 }
772 }
773
774 return EFI_SUCCESS;
775}
776
777EFI_STATUS
778EFIAPI
780 IN HDA_CODEC_DEV *HdaCodecDev
781 )
782{
783 // DEBUG((DEBUG_INFO, "HdaCodecProbeCodec(): start\n"));
784
785 // Create variables.
786 EFI_STATUS Status;
787 EFI_HDA_IO_PROTOCOL *HdaIo = HdaCodecDev->HdaIo;
788 UINT32 Response;
789 UINT8 FuncStart;
790 UINT8 FuncEnd;
791 UINT8 FuncCount;
792
793 // Get vendor and device ID.
794 Status = HdaIo->SendCommand (
795 HdaIo,
798 &HdaCodecDev->VendorId
799 );
800 if (EFI_ERROR (Status)) {
801 return Status;
802 }
803
804 DEBUG ((DEBUG_INFO, "HDA: | Codec ID: 0x%X:0x%X\n", HDA_PARAMETER_VENDOR_ID_VEN (HdaCodecDev->VendorId), HDA_PARAMETER_VENDOR_ID_DEV (HdaCodecDev->VendorId)));
805
806 // Get revision ID.
807 Status = HdaIo->SendCommand (
808 HdaIo,
811 &HdaCodecDev->RevisionId
812 );
813 if (EFI_ERROR (Status)) {
814 return Status;
815 }
816
817 // Try to match codec name.
818 HdaCodecDev->Name = AsciiStrCopyToUnicode (OcHdaCodecGetName (HdaCodecDev->VendorId, (UINT16)HdaCodecDev->RevisionId), 0);
819 DEBUG ((DEBUG_INFO, "HDA: | Codec name: %s\n", HdaCodecDev->Name));
820
821 // Get function group count.
822 Status = HdaIo->SendCommand (
823 HdaIo,
826 &Response
827 );
828 if (EFI_ERROR (Status)) {
829 return Status;
830 }
831
832 FuncStart = HDA_PARAMETER_SUBNODE_COUNT_START (Response);
833 FuncCount = HDA_PARAMETER_SUBNODE_COUNT_TOTAL (Response);
834 FuncEnd = FuncStart + FuncCount - 1;
835 DEBUG ((DEBUG_INFO, "HDA: | Codec contains %u function groups, start @ 0x%X, end @ 0x%X\n", FuncCount, FuncStart, FuncEnd));
836
837 // Ensure there are functions.
838 if (FuncCount == 0) {
839 return EFI_UNSUPPORTED;
840 }
841
842 // Allocate space for function groups.
843 HdaCodecDev->FuncGroups = AllocateZeroPool (sizeof (HDA_FUNC_GROUP) * FuncCount);
844 if (HdaCodecDev->FuncGroups == NULL) {
845 return EFI_OUT_OF_RESOURCES;
846 }
847
848 HdaCodecDev->FuncGroupsCount = FuncCount;
849 HdaCodecDev->AudioFuncGroup = NULL;
850
851 // Probe functions.
852 for (UINT8 i = 0; i < FuncCount; i++) {
853 HdaCodecDev->FuncGroups[i].HdaCodecDev = HdaCodecDev;
854 HdaCodecDev->FuncGroups[i].NodeId = FuncStart + i;
855 Status = HdaCodecProbeFuncGroup (HdaCodecDev->FuncGroups + i);
856 if (!(EFI_ERROR (Status)) && (HdaCodecDev->AudioFuncGroup == NULL)) {
857 HdaCodecDev->AudioFuncGroup = HdaCodecDev->FuncGroups + i;
858 }
859 }
860
861 // Do not support codecs without audio function groups (i.e. modem codecs).
862 if (HdaCodecDev->AudioFuncGroup == NULL) {
863 DEBUG ((DEBUG_INFO, "HDA: | Codec contains no audio function groups\n"));
864 return EFI_UNSUPPORTED;
865 }
866
867 return EFI_SUCCESS;
868}
869
870EFI_STATUS
871EFIAPI
873 IN HDA_WIDGET_DEV *HdaWidget,
874 IN UINT8 Level
875 )
876{
877 // DEBUG((DEBUG_INFO, "HdaCodecFindUpstreamOutput(): start\n"));
878
879 // If level is above 15, we may have entered an infinite loop so just give up.
880 if (Level > 15) {
881 return EFI_ABORTED;
882 }
883
884 // Create variables.
885 EFI_STATUS Status;
886 HDA_WIDGET_DEV *HdaConnectedWidget;
887
888 // Go through connections and check for Output widgets.
889 for (UINT8 c = 0; c < HdaWidget->ConnectionCount; c++) {
890 // Get connected widget.
891 HdaConnectedWidget = HdaWidget->WidgetConnections[c];
892 DEBUG ((
893 DEBUG_INFO,
894 "HDA: | %*aWidget @ 0x%X (type 0x%X)\n",
895 Level,
896 " ",
897 HdaConnectedWidget->NodeId,
898 HdaConnectedWidget->Type
899 ));
900
901 // If this is an Output, we are done.
902 if (HdaConnectedWidget->Type == HDA_WIDGET_TYPE_OUTPUT) {
903 HdaWidget->UpstreamWidget = HdaConnectedWidget;
904 HdaWidget->UpstreamIndex = c;
905 return EFI_SUCCESS;
906 }
907
908 // Check connections of connected widget.
909 // If a success status is returned, that means an Output widget was found and we are done.
910 Status = HdaCodecFindUpstreamOutput (HdaConnectedWidget, Level + 1);
911 if (Status == EFI_SUCCESS) {
912 HdaWidget->UpstreamWidget = HdaConnectedWidget;
913 HdaWidget->UpstreamIndex = c;
914 return EFI_SUCCESS;
915 }
916 }
917
918 // We didn't find an Output if we got here (probably zero connections).
919 return EFI_NOT_FOUND;
920}
921
922EFI_STATUS
923EFIAPI
925 IN HDA_CODEC_DEV *HdaCodecDev
926 )
927{
928 EFI_STATUS Status;
929 EFI_HDA_IO_PROTOCOL *HdaIo;
930 HDA_FUNC_GROUP *HdaFuncGroup;
931 HDA_WIDGET_DEV *HdaWidget;
932 UINT8 DefaultDeviceType;
933 UINT32 Response;
934 BOOLEAN IsOutput;
935
936 // DEBUG((DEBUG_INFO, "HdaCodecParsePorts(): start\n"));
937
938 HdaIo = HdaCodecDev->HdaIo;
939
940 // Loop through each function group.
941 for (UINT8 f = 0; f < HdaCodecDev->FuncGroupsCount; f++) {
942 // Get function group.
943 HdaFuncGroup = HdaCodecDev->FuncGroups + f;
944
945 // Loop through each widget.
946 for (UINT8 w = 0; w < HdaFuncGroup->WidgetsCount; w++) {
947 // Get widget.
948 HdaWidget = HdaFuncGroup->Widgets + w;
949
950 // Is the widget a pin complex? If not, ignore it.
951 // If this is a pin complex but it has no connection to a port, also ignore it.
952 // If the default association for the pin complex is zero, also ignore it.
953 if ((HdaWidget->Type != HDA_WIDGET_TYPE_PIN_COMPLEX) ||
956 {
957 DEBUG ((
958 DEBUG_VERBOSE,
959 "HDA: | Ignoring widget @ 0x%X\n",
960 HdaWidget->NodeId
961 ));
962 continue;
963 }
964
965 if (PcdGetBool (PcdAudioControllerUsePinCapsForOutputs)) {
966 // Use PinCaps to identify all pin complexes which can be configured as outputs.
967 // On certain systes, e.g. MacPro5,1, ports which are inputs according to default
968 // type are the correct output channels to use on the system.
969 IsOutput = (HdaWidget->PinCapabilities & HDA_PARAMETER_PIN_CAPS_OUTPUT) != 0;
970 } else {
971 // Determine if port is an output based on the default device type.
972 // The types reported here do not correspond particularly well to the real hardware.
974
975 IsOutput = (DefaultDeviceType == HDA_CONFIG_DEFAULT_DEVICE_LINE_OUT)
976 || (DefaultDeviceType == HDA_CONFIG_DEFAULT_DEVICE_SPEAKER)
977 || (DefaultDeviceType == HDA_CONFIG_DEFAULT_DEVICE_HEADPHONE_OUT)
978 || (DefaultDeviceType == HDA_CONFIG_DEFAULT_DEVICE_SPDIF_OUT)
979 || (DefaultDeviceType == HDA_CONFIG_DEFAULT_DEVICE_OTHER_DIGITAL_OUT);
980 }
981
982 if (IsOutput) {
983 // Try to get upstream output.
984 Status = HdaCodecFindUpstreamOutput (HdaWidget, 0);
985 if (EFI_ERROR (Status)) {
986 DEBUG ((
987 DEBUG_WARN,
988 "HDA: Widget @ 0x%X find upstream output - %r\n",
989 HdaWidget->NodeId,
990 Status
991 ));
992 continue;
993 }
994
995 // Report output.
996 DEBUG ((
997 DEBUG_INFO,
998 "HDA: | Port widget @ 0x%X is an output (pin defaults 0x%X) (bitmask %u)\n",
999 HdaWidget->NodeId,
1000 HdaWidget->DefaultConfiguration,
1001 1 << HdaCodecDev->OutputPortsCount
1002 ));
1003
1004 // If EAPD is present, enable.
1006 // Get current EAPD setting.
1007 Status = HdaIo->SendCommand (HdaIo, HdaWidget->NodeId, HDA_CODEC_VERB (HDA_VERB_GET_EAPD_BTL_ENABLE, 0), &Response);
1008 if (EFI_ERROR (Status)) {
1009 return Status;
1010 }
1011
1012 // If the EAPD is not set, set it.
1013 if (!(Response & HDA_EAPD_BTL_ENABLE_EAPD)) {
1014 Response |= HDA_EAPD_BTL_ENABLE_EAPD;
1015 Status = HdaIo->SendCommand (
1016 HdaIo,
1017 HdaWidget->NodeId,
1020 (UINT8)Response
1021 ),
1022 &Response
1023 );
1024 if (EFI_ERROR (Status)) {
1025 return Status;
1026 }
1027 }
1028 }
1029
1030 // If the output amp supports muting, unmute.
1032 UINT8 offset = HDA_PARAMETER_AMP_CAPS_OFFSET (HdaWidget->AmpOutCapabilities); // TODO set volume.
1033
1034 // If there are no overriden amp capabilities, check function group.
1035 if (!(HdaWidget->AmpOverride)) {
1037 }
1038
1039 // Unmute amp.
1040 Status = HdaIo->SendCommand (
1041 HdaIo,
1042 HdaWidget->NodeId,
1045 HDA_VERB_SET_AMP_GAIN_MUTE_PAYLOAD (0, offset, FALSE, TRUE, TRUE, FALSE, TRUE)
1046 ),
1047 &Response
1048 );
1049 if (EFI_ERROR (Status)) {
1050 return Status;
1051 }
1052 }
1053
1054 // Reallocate output array.
1055 HdaCodecDev->OutputPorts = ReallocatePool (sizeof (HDA_WIDGET_DEV *) * HdaCodecDev->OutputPortsCount, sizeof (HDA_WIDGET_DEV *) * (HdaCodecDev->OutputPortsCount + 1), HdaCodecDev->OutputPorts);
1056 if (HdaCodecDev->OutputPorts == NULL) {
1057 return EFI_OUT_OF_RESOURCES;
1058 }
1059
1060 HdaCodecDev->OutputPortsCount++;
1061
1062 // Add widget to output array.
1063 HdaCodecDev->OutputPorts[HdaCodecDev->OutputPortsCount - 1] = HdaWidget;
1064 }
1065 }
1066 }
1067
1068 // Wait for all widgets to fully come on.
1069 if (gCodecSetupDelay != 0) {
1071 }
1072
1073 return EFI_SUCCESS;
1074}
1075
1076EFI_STATUS
1077EFIAPI
1079 IN HDA_CODEC_DEV *HdaCodecDev
1080 )
1081{
1082 // Create variables.
1083 EFI_STATUS Status;
1084 HDA_CODEC_INFO_PRIVATE_DATA *HdaCodecInfoData;
1085 AUDIO_IO_PRIVATE_DATA *AudioIoData;
1086
1087 // Allocate space for protocol data.
1088 HdaCodecInfoData = AllocateZeroPool (sizeof (HDA_CODEC_INFO_PRIVATE_DATA));
1089 AudioIoData = AllocateZeroPool (sizeof (AUDIO_IO_PRIVATE_DATA));
1090 if ((HdaCodecInfoData == NULL) || (AudioIoData == NULL)) {
1091 Status = EFI_OUT_OF_RESOURCES;
1092 goto FREE_POOLS;
1093 }
1094
1095 // Populate info protocol data.
1096 HdaCodecInfoData->Signature = HDA_CODEC_PRIVATE_DATA_SIGNATURE;
1097 HdaCodecInfoData->HdaCodecDev = HdaCodecDev;
1099 HdaCodecInfoData->HdaCodecInfo.GetName = HdaCodecInfoGetCodecName;
1107 HdaCodecDev->HdaCodecInfoData = HdaCodecInfoData;
1108
1109 // Populate I/O protocol data.
1111 AudioIoData->HdaCodecDev = HdaCodecDev;
1119 HdaCodecDev->AudioIoData = AudioIoData;
1120
1121 // Install protocols.
1122 Status = gBS->InstallMultipleProtocolInterfaces (
1123 &HdaCodecDev->ControllerHandle,
1125 &HdaCodecInfoData->HdaCodecInfo,
1127 &AudioIoData->AudioIo,
1128 &gEfiCallerIdGuid,
1129 HdaCodecDev,
1130 NULL
1131 );
1132 if (EFI_ERROR (Status)) {
1133 goto FREE_POOLS;
1134 }
1135
1136 DEBUG ((DEBUG_INFO, "HDA: Codec protocols installed\n"));
1137 return EFI_SUCCESS;
1138
1139FREE_POOLS:
1140 if (HdaCodecInfoData != NULL) {
1141 FreePool (HdaCodecInfoData);
1142 }
1143
1144 if (AudioIoData != NULL) {
1145 FreePool (AudioIoData);
1146 }
1147
1148 return Status;
1149}
1150
1151EFI_STATUS
1152EFIAPI
1154 IN HDA_WIDGET_DEV *HdaWidget,
1155 OUT HDA_WIDGET_DEV **HdaOutputWidget
1156 )
1157{
1158 DEBUG ((DEBUG_VERBOSE, "HdaCodecGetOutputDac(): start\n"));
1159
1160 // Check that parameters are valid.
1161 if ((HdaWidget == NULL) || (HdaOutputWidget == NULL)) {
1162 return EFI_INVALID_PARAMETER;
1163 }
1164
1165 // Crawl through widget path looking for output DAC.
1166 while (HdaWidget != NULL) {
1167 // Is this widget an output DAC?
1168 if (HdaWidget->Type == HDA_WIDGET_TYPE_OUTPUT) {
1169 *HdaOutputWidget = HdaWidget;
1170 return EFI_SUCCESS;
1171 }
1172
1173 // Move to upstream widget.
1174 HdaWidget = HdaWidget->UpstreamWidget;
1175 }
1176
1177 // If we get here, we couldn't find the DAC.
1178 return EFI_NOT_FOUND;
1179}
1180
1181EFI_STATUS
1182EFIAPI
1184 IN HDA_WIDGET_DEV *HdaPinWidget,
1185 OUT UINT32 *SupportedRates
1186 )
1187{
1188 DEBUG ((DEBUG_VERBOSE, "HdaCodecGetSupportedPcmRates(): start\n"));
1189
1190 // Check that parameters are valid.
1191 if ((HdaPinWidget == NULL) || (SupportedRates == NULL)) {
1192 return EFI_INVALID_PARAMETER;
1193 }
1194
1195 // Create variables.
1196 EFI_STATUS Status;
1197 HDA_WIDGET_DEV *HdaOutputWidget;
1198
1199 // Get output DAC widget.
1200 Status = HdaCodecGetOutputDac (HdaPinWidget, &HdaOutputWidget);
1201 if (EFI_ERROR (Status)) {
1202 return Status;
1203 }
1204
1205 // Does the widget specify format info?
1207 // Check widget for PCM support.
1209 return EFI_UNSUPPORTED;
1210 }
1211
1212 *SupportedRates = HdaOutputWidget->SupportedPcmRates;
1213 } else {
1214 // Check function group for PCM support.
1216 return EFI_UNSUPPORTED;
1217 }
1218
1219 *SupportedRates = HdaOutputWidget->FuncGroup->SupportedPcmRates;
1220 }
1221
1222 DEBUG ((DEBUG_VERBOSE, "HdaCodecGetSupportedPcmRates(): supported rates - 0x%X\n", *SupportedRates));
1223 return EFI_SUCCESS;
1224}
1225
1226EFI_STATUS
1227EFIAPI
1229 IN HDA_WIDGET_DEV *HdaWidget
1230 )
1231{
1232 // DEBUG((DEBUG_INFO, "HdaCodecDisableWidgetPath(): start\n"));
1233
1234 // Check if widget is valid.
1235 if (HdaWidget == NULL) {
1236 return EFI_INVALID_PARAMETER;
1237 }
1238
1239 // Create variables.
1240 EFI_STATUS Status;
1241 EFI_HDA_IO_PROTOCOL *HdaIo = HdaWidget->FuncGroup->HdaCodecDev->HdaIo;
1242 UINT32 Response;
1243
1244 // Crawl through widget path.
1245 while (HdaWidget != NULL) {
1246 // If Output, disable stream.
1247 if (HdaWidget->Type == HDA_WIDGET_TYPE_OUTPUT) {
1248 Status = HdaIo->SendCommand (
1249 HdaIo,
1250 HdaWidget->NodeId,
1254 ),
1255 &Response
1256 );
1257 if (EFI_ERROR (Status)) {
1258 return Status;
1259 }
1260 }
1261
1262 // If widget is a pin complex, disable output.
1263 if (HdaWidget->Type == HDA_WIDGET_TYPE_PIN_COMPLEX) {
1264 Status = HdaIo->SendCommand (
1265 HdaIo,
1266 HdaWidget->NodeId,
1269 HDA_VERB_SET_PIN_WIDGET_CONTROL_PAYLOAD (0, FALSE, FALSE, FALSE)
1270 ),
1271 &Response
1272 );
1273 if (EFI_ERROR (Status)) {
1274 return Status;
1275 }
1276 }
1277
1278 // Move to upstream widget.
1279 HdaWidget = HdaWidget->UpstreamWidget;
1280 }
1281
1282 // Path disabled.
1283 return EFI_SUCCESS;
1284}
1285
1286EFI_STATUS
1287EFIAPI
1289 IN HDA_WIDGET_DEV *HdaWidget,
1290 IN UINT8 GainParam,
1291 OUT INT8 *Gain
1292 )
1293{
1294 UINT8 Offset;
1295 UINT8 NumSteps;
1296 UINT8 StepSize;
1297
1298 // Check if widget is valid.
1299 if (HdaWidget == NULL) {
1300 return EFI_INVALID_PARAMETER;
1301 }
1302
1303 // Crawl through widget path.
1304 while (HdaWidget != NULL) {
1305 DEBUG ((DEBUG_INFO, "HDA: Widget @ 0x%X calculating gain\n", HdaWidget->NodeId));
1306
1307 // If there is an output amp, use its parameters.
1308 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_OUT_AMP) {
1309 // If there are no overriden amp capabilities, check function group.
1310 if (HdaWidget->AmpOverride) {
1311 Offset = HDA_PARAMETER_AMP_CAPS_OFFSET (HdaWidget->AmpOutCapabilities);
1312 NumSteps = HDA_PARAMETER_AMP_CAPS_NUM_STEPS (HdaWidget->AmpOutCapabilities);
1313 StepSize = HDA_PARAMETER_AMP_CAPS_STEP_SIZE (HdaWidget->AmpOutCapabilities);
1314 } else {
1315 Offset = HDA_PARAMETER_AMP_CAPS_OFFSET (HdaWidget->FuncGroup->AmpOutCapabilities);
1316 NumSteps = HDA_PARAMETER_AMP_CAPS_NUM_STEPS (HdaWidget->FuncGroup->AmpOutCapabilities);
1317 StepSize = HDA_PARAMETER_AMP_CAPS_STEP_SIZE (HdaWidget->FuncGroup->AmpOutCapabilities);
1318 }
1319
1320 // Ignore any fixed volume amps.
1321 if (NumSteps > 0) {
1322 if (GainParam > NumSteps) {
1323 return EFI_INVALID_PARAMETER;
1324 }
1325
1326 // Calculate decibel gain from widget gain param.
1327 *Gain = ((INTN)GainParam - Offset) * (StepSize + 1) / 4;
1328
1329 DEBUG ((DEBUG_INFO, "HDA: Calculated amp gain %d dB (from 0x%X raw)\n", *Gain, GainParam));
1330
1331 return EFI_SUCCESS;
1332 }
1333 }
1334
1335 // Move to upstream widget.
1336 HdaWidget = HdaWidget->UpstreamWidget;
1337 }
1338
1339 return EFI_NOT_FOUND;
1340}
1341
1342EFI_STATUS
1343EFIAPI
1345 IN HDA_WIDGET_DEV *HdaWidget,
1346 IN INT8 Gain,
1347 IN UINT8 StreamId,
1348 IN UINT16 StreamFormat
1349 )
1350{
1351 EFI_STATUS Status;
1352 EFI_HDA_IO_PROTOCOL *HdaIo;
1353 UINT32 Response;
1354 UINT8 VrefCaps;
1355 UINT8 VrefCtrl;
1356 UINT8 Offset;
1357 UINT8 NumSteps;
1358 UINT8 StepSize;
1359 INTN GainParam;
1360
1361 // DEBUG((DEBUG_INFO, "HdaCodecEnableWidgetPath(): start\n"));
1362
1363 // Check if widget is valid.
1364 if (HdaWidget == NULL) {
1365 return EFI_INVALID_PARAMETER;
1366 }
1367
1368 HdaIo = HdaWidget->FuncGroup->HdaCodecDev->HdaIo;
1369
1370 // Crawl through widget path.
1371 while (HdaWidget != NULL) {
1372 DEBUG ((DEBUG_INFO, "HDA: Widget @ 0x%X setting up\n", HdaWidget->NodeId));
1373
1374 // If pin complex, set as output.
1375 if (HdaWidget->Type == HDA_WIDGET_TYPE_PIN_COMPLEX) {
1376 VrefCaps = HDA_PARAMETER_PIN_CAPS_VREF (HdaWidget->PinCapabilities);
1377
1378 // If voltage reference control is available, choose the lowest supported voltage.
1379 // This is similar to how Linux drivers enable audio e.g. on Realtek devices on Mac,
1380 // but this is an attempt to make a more general purpose system.
1381 // REF: https://github.com/torvalds/linux/blob/6f513529296fd4f696afb4354c46508abe646541/sound/pci/hda/patch_realtek.c#L1999-L2012
1383 if (VrefCaps & HDA_PARAMETER_PIN_CAPS_VREF_50) {
1385 } else if (VrefCaps & HDA_PARAMETER_PIN_CAPS_VREF_80) {
1387 } else if (VrefCaps & HDA_PARAMETER_PIN_CAPS_VREF_100) {
1389 }
1390
1391 Status = HdaIo->SendCommand (
1392 HdaIo,
1393 HdaWidget->NodeId,
1396 HDA_VERB_SET_PIN_WIDGET_CONTROL_PAYLOAD (VrefCtrl, FALSE, TRUE, FALSE)
1397 ),
1398 &Response
1399 );
1400 DEBUG ((
1401 EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_INFO,
1402 "HDA: Widget @ 0x%X enable output amp vref %u - %r\n",
1403 HdaWidget->NodeId,
1404 VrefCtrl,
1405 Status
1406 ));
1407 if (EFI_ERROR (Status)) {
1408 return Status;
1409 }
1410
1411 // If EAPD, enable.
1412 if (HdaWidget->PinCapabilities & HDA_PARAMETER_PIN_CAPS_EAPD) {
1413 // Get current EAPD setting.
1414 Status = HdaIo->SendCommand (HdaIo, HdaWidget->NodeId, HDA_CODEC_VERB (HDA_VERB_GET_EAPD_BTL_ENABLE, 0), &Response);
1415 if (EFI_ERROR (Status)) {
1416 return Status;
1417 }
1418
1419 // If the EAPD is not set, set it.
1420 if (!(Response & HDA_EAPD_BTL_ENABLE_EAPD)) {
1421 Response |= HDA_EAPD_BTL_ENABLE_EAPD;
1422 Status = HdaIo->SendCommand (
1423 HdaIo,
1424 HdaWidget->NodeId,
1427 (UINT8)Response
1428 ),
1429 &Response
1430 );
1431 if (EFI_ERROR (Status)) {
1432 return Status;
1433 }
1434 }
1435 }
1436 }
1437
1438 // If this is a digital widget, enable digital output.
1439 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_DIGITAL) {
1440 // Enable digital output.
1441 Status = HdaIo->SendCommand (
1442 HdaIo,
1443 HdaWidget->NodeId,
1447 ),
1448 &Response
1449 );
1450 if (EFI_ERROR (Status)) {
1451 return Status;
1452 }
1453
1454 Status = HdaIo->SendCommand (
1455 HdaIo,
1456 HdaWidget->NodeId,
1459 0x00
1460 ),
1461 &Response
1462 );
1463 if (EFI_ERROR (Status)) {
1464 return Status;
1465 }
1466
1467 Status = HdaIo->SendCommand (
1468 HdaIo,
1469 HdaWidget->NodeId,
1472 0x11
1473 ),
1474 &Response
1475 );
1476 if (EFI_ERROR (Status)) {
1477 return Status;
1478 }
1479 }
1480
1481 // If there is an output amp, unmute.
1482 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_OUT_AMP) {
1483 // If there are no overriden amp capabilities, check function group.
1484 if (HdaWidget->AmpOverride) {
1485 Offset = HDA_PARAMETER_AMP_CAPS_OFFSET (HdaWidget->AmpOutCapabilities);
1486 NumSteps = HDA_PARAMETER_AMP_CAPS_NUM_STEPS (HdaWidget->AmpOutCapabilities);
1487 StepSize = HDA_PARAMETER_AMP_CAPS_STEP_SIZE (HdaWidget->AmpOutCapabilities);
1488 } else {
1489 Offset = HDA_PARAMETER_AMP_CAPS_OFFSET (HdaWidget->FuncGroup->AmpOutCapabilities);
1490 NumSteps = HDA_PARAMETER_AMP_CAPS_NUM_STEPS (HdaWidget->FuncGroup->AmpOutCapabilities);
1491 StepSize = HDA_PARAMETER_AMP_CAPS_STEP_SIZE (HdaWidget->FuncGroup->AmpOutCapabilities);
1492 }
1493
1494 // Calculate gain param.
1495 GainParam = (Gain * 4 / (StepSize + 1)) + Offset;
1496 if (GainParam > NumSteps) {
1497 GainParam = NumSteps;
1498 } else if (GainParam < 0) {
1499 GainParam = 0;
1500 }
1501
1502 DEBUG ((DEBUG_INFO, "HDA: Applying amp gain 0x%X (from %d dB)\n", GainParam, Gain));
1503 Status = HdaIo->SendCommand (
1504 HdaIo,
1505 HdaWidget->NodeId,
1508 HDA_VERB_SET_AMP_GAIN_MUTE_PAYLOAD (0, GainParam, FALSE, TRUE, TRUE, FALSE, TRUE)
1509 ),
1510 &Response
1511 );
1512 if (EFI_ERROR (Status)) {
1513 return Status;
1514 }
1515 }
1516
1517 // If there are input amps, mute all but the upstream.
1518 if (HdaWidget->Capabilities & HDA_PARAMETER_WIDGET_CAPS_IN_AMP) {
1519 DEBUG ((DEBUG_INFO, "HDA: Widget @ 0x%X in amp\n", HdaWidget->NodeId));
1520 for (UINT8 c = 0; c < HdaWidget->ConnectionCount; c++) {
1521 if (HdaWidget->UpstreamIndex == c) {
1522 UINT8 offset = HDA_PARAMETER_AMP_CAPS_OFFSET (HdaWidget->AmpInCapabilities);
1523 // If there are no overriden amp capabilities, check function group.
1524 if (!(HdaWidget->AmpOverride)) {
1525 offset = HDA_PARAMETER_AMP_CAPS_OFFSET (HdaWidget->FuncGroup->AmpInCapabilities);
1526 }
1527
1528 Status = HdaIo->SendCommand (
1529 HdaIo,
1530 HdaWidget->NodeId,
1533 HDA_VERB_SET_AMP_GAIN_MUTE_PAYLOAD (c, offset, FALSE, TRUE, TRUE, TRUE, FALSE)
1534 ),
1535 &Response
1536 );
1537 if (EFI_ERROR (Status)) {
1538 return Status;
1539 }
1540 } else {
1541 Status = HdaIo->SendCommand (
1542 HdaIo,
1543 HdaWidget->NodeId,
1546 HDA_VERB_SET_AMP_GAIN_MUTE_PAYLOAD (c, 0, TRUE, TRUE, TRUE, TRUE, FALSE)
1547 ),
1548 &Response
1549 );
1550 if (EFI_ERROR (Status)) {
1551 return Status;
1552 }
1553 }
1554 }
1555 }
1556
1557 // If there is more than one connection, select our upstream.
1558 if (HdaWidget->ConnectionCount > 1) {
1559 Status = HdaIo->SendCommand (
1560 HdaIo,
1561 HdaWidget->NodeId,
1564 HdaWidget->UpstreamIndex
1565 ),
1566 &Response
1567 );
1568 if (EFI_ERROR (Status)) {
1569 return Status;
1570 }
1571 }
1572
1573 // If Output, set up stream.
1574 if (HdaWidget->Type == HDA_WIDGET_TYPE_OUTPUT) {
1575 DEBUG ((DEBUG_INFO, "HDA: Widget @ 0x%X output\n", HdaWidget->NodeId));
1576 Status = HdaIo->SendCommand (
1577 HdaIo,
1578 HdaWidget->NodeId,
1581 StreamFormat
1582 ),
1583 &Response
1584 );
1585 if (EFI_ERROR (Status)) {
1586 return Status;
1587 }
1588
1589 Status = HdaIo->SendCommand (
1590 HdaIo,
1591 HdaWidget->NodeId,
1595 ),
1596 &Response
1597 );
1598 if (EFI_ERROR (Status)) {
1599 return Status;
1600 }
1601 }
1602
1603 // Move to upstream widget.
1604 HdaWidget = HdaWidget->UpstreamWidget;
1605 }
1606
1607 return EFI_SUCCESS;
1608}
1609
1610VOID
1611EFIAPI
1613 IN HDA_CODEC_DEV *HdaCodecDev
1614 )
1615{
1616 DEBUG ((DEBUG_VERBOSE, "HdaCodecCleanup(): start\n"));
1617
1618 // Create variables.
1619 EFI_STATUS Status;
1620 HDA_FUNC_GROUP *HdaFuncGroup;
1621 HDA_WIDGET_DEV *HdaWidget;
1622
1623 // If codec is already clear, we are done.
1624 if (HdaCodecDev == NULL) {
1625 return;
1626 }
1627
1628 // Clean HDA Codec Info protocol.
1629 if (HdaCodecDev->HdaCodecInfoData != NULL) {
1630 // Uninstall protocol.
1631 DEBUG ((DEBUG_VERBOSE, "HdaCodecCleanup(): clean Hda Codec Info\n"));
1632 Status = gBS->UninstallProtocolInterface (
1633 HdaCodecDev->ControllerHandle,
1635 &HdaCodecDev->HdaCodecInfoData->HdaCodecInfo
1636 );
1637 ASSERT_EFI_ERROR (Status);
1638
1639 // Free data.
1640 FreePool (HdaCodecDev->HdaCodecInfoData);
1641 }
1642
1643 // Clean Audio I/O protocol.
1644 if (HdaCodecDev->AudioIoData != NULL) {
1645 // Uninstall protocol.
1646 DEBUG ((DEBUG_VERBOSE, "HdaCodecCleanup(): clean Audio I/O\n"));
1647 Status = gBS->UninstallProtocolInterface (
1648 HdaCodecDev->ControllerHandle,
1650 &HdaCodecDev->AudioIoData->AudioIo
1651 );
1652 ASSERT_EFI_ERROR (Status);
1653
1654 // Free data.
1655 FreePool (HdaCodecDev->AudioIoData);
1656 }
1657
1658 // Clean up input and output port arrays.
1659 if (HdaCodecDev->OutputPorts != NULL) {
1660 FreePool (HdaCodecDev->OutputPorts);
1661 }
1662
1663 if (HdaCodecDev->InputPorts != NULL) {
1664 FreePool (HdaCodecDev->InputPorts);
1665 }
1666
1667 // Clean function groups.
1668 if (HdaCodecDev->FuncGroups != NULL) {
1669 // Clean each function group.
1670 for (UINT8 f = 0; f < HdaCodecDev->FuncGroupsCount; f++) {
1671 HdaFuncGroup = HdaCodecDev->FuncGroups + f;
1672
1673 // Clean widgets in function group.
1674 if (HdaFuncGroup->Widgets != NULL) {
1675 for (UINT8 w = 0; w < HdaFuncGroup->WidgetsCount; w++) {
1676 HdaWidget = HdaFuncGroup->Widgets + w;
1677
1678 // Clean input amp default arrays.
1679 if (HdaWidget->AmpInLeftDefaultGainMute != NULL) {
1680 FreePool (HdaWidget->AmpInLeftDefaultGainMute);
1681 }
1682
1683 if (HdaWidget->AmpInRightDefaultGainMute != NULL) {
1684 FreePool (HdaWidget->AmpInRightDefaultGainMute);
1685 }
1686
1687 // Clean connections array.
1688 if (HdaWidget->WidgetConnections != NULL) {
1689 FreePool (HdaWidget->WidgetConnections);
1690 }
1691
1692 if (HdaWidget->Connections != NULL) {
1693 FreePool (HdaWidget->Connections);
1694 }
1695 }
1696
1697 // Free widgets array.
1698 FreePool (HdaFuncGroup->Widgets);
1699 }
1700 }
1701
1702 // Free function group array.
1703 FreePool (HdaCodecDev->FuncGroups);
1704 }
1705
1706 // Free codec device.
1707 gBS->UninstallProtocolInterface (
1708 HdaCodecDev->ControllerHandle,
1709 &gEfiCallerIdGuid,
1710 HdaCodecDev
1711 );
1712 FreePool (HdaCodecDev);
1713}
1714
1715EFI_STATUS
1716EFIAPI
1718 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1719 IN EFI_HANDLE ControllerHandle,
1720 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1721 )
1722{
1723 // Create variables.
1724 EFI_STATUS Status;
1725 EFI_HDA_IO_PROTOCOL *HdaIo;
1726 UINT8 CodecAddress;
1727
1728 // Attempt to open the HDA codec protocol. If it can be opened, we can support it.
1729 Status = gBS->OpenProtocol (
1730 ControllerHandle,
1732 (VOID **)&HdaIo,
1733 This->DriverBindingHandle,
1734 ControllerHandle,
1735 EFI_OPEN_PROTOCOL_BY_DRIVER
1736 );
1737 if (EFI_ERROR (Status)) {
1738 return Status;
1739 }
1740
1741 // Get address of codec.
1742 Status = HdaIo->GetAddress (HdaIo, &CodecAddress);
1743 if (EFI_ERROR (Status)) {
1744 goto CLOSE_CODEC;
1745 }
1746
1747 // Check --force-codec.
1748 if (gUseForcedCodec && (gForcedCodec != CodecAddress)) {
1749 Status = EFI_UNSUPPORTED;
1750 goto CLOSE_CODEC;
1751 }
1752
1753 // Codec can be supported.
1754 DEBUG ((DEBUG_INFO, "HDA: Connecting codec 0x%X\n", CodecAddress));
1755 Status = EFI_SUCCESS;
1756
1757CLOSE_CODEC:
1758 // Close protocol.
1759 gBS->CloseProtocol (ControllerHandle, &gEfiHdaIoProtocolGuid, This->DriverBindingHandle, ControllerHandle);
1760 return Status;
1761}
1762
1763EFI_STATUS
1764EFIAPI
1766 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1767 IN EFI_HANDLE ControllerHandle,
1768 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1769 )
1770{
1771 DEBUG ((DEBUG_VERBOSE, "HdaCodecDriverBindingStart(): start\n"));
1772
1773 // Create variables.
1774 EFI_STATUS Status;
1775 EFI_HDA_IO_PROTOCOL *HdaIo;
1776 EFI_DEVICE_PATH_PROTOCOL *HdaCodecDevicePath;
1777 HDA_CODEC_DEV *HdaCodecDev;
1778
1779 // Open HDA I/O protocol.
1780 Status = gBS->OpenProtocol (
1781 ControllerHandle,
1783 (VOID **)&HdaIo,
1784 This->DriverBindingHandle,
1785 ControllerHandle,
1786 EFI_OPEN_PROTOCOL_BY_DRIVER
1787 );
1788 if (EFI_ERROR (Status)) {
1789 return Status;
1790 }
1791
1792 // Open Device Path protocol.
1793 Status = gBS->OpenProtocol (
1794 ControllerHandle,
1796 (VOID **)&HdaCodecDevicePath,
1797 This->DriverBindingHandle,
1798 ControllerHandle,
1799 EFI_OPEN_PROTOCOL_BY_DRIVER
1800 );
1801 if (EFI_ERROR (Status)) {
1802 goto CLOSE_CODEC;
1803 }
1804
1805 // Allocate codec device.
1806 HdaCodecDev = AllocateZeroPool (sizeof (HDA_CODEC_DEV));
1807 if (HdaCodecDev == NULL) {
1808 Status = EFI_OUT_OF_RESOURCES;
1809 goto CLOSE_CODEC;
1810 }
1811
1812 // Fill codec device data.
1814 HdaCodecDev->HdaIo = HdaIo;
1815 HdaCodecDev->DevicePath = HdaCodecDevicePath;
1816 HdaCodecDev->ControllerHandle = ControllerHandle;
1817
1818 // Probe codec.
1819 Status = HdaCodecProbeCodec (HdaCodecDev);
1820 if (EFI_ERROR (Status)) {
1821 goto FREE_CODEC;
1822 }
1823
1824 // Get ports.
1825 Status = HdaCodecParsePorts (HdaCodecDev);
1826 if (EFI_ERROR (Status)) {
1827 goto FREE_CODEC;
1828 }
1829
1830 // Publish protocols.
1831 Status = HdaCodecInstallProtocols (HdaCodecDev);
1832 ASSERT_EFI_ERROR (Status);
1833 if (EFI_ERROR (Status)) {
1834 goto FREE_CODEC;
1835 }
1836
1837 // Success.
1838 DEBUG ((DEBUG_INFO, "HDA: Codec initialized\n"));
1839 return EFI_SUCCESS;
1840
1841FREE_CODEC:
1842 // Cleanup codec.
1843 HdaCodecCleanup (HdaCodecDev);
1844
1845CLOSE_CODEC:
1846 // Close protocols.
1847 gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle);
1848 gBS->CloseProtocol (ControllerHandle, &gEfiHdaIoProtocolGuid, This->DriverBindingHandle, ControllerHandle);
1849 return Status;
1850}
1851
1852EFI_STATUS
1853EFIAPI
1855 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1856 IN EFI_HANDLE ControllerHandle,
1857 IN UINTN NumberOfChildren,
1858 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
1859 )
1860{
1861 DEBUG ((DEBUG_VERBOSE, "HdaCodecDriverBindingStop(): start\n"));
1862
1863 // Create variables.
1864 EFI_STATUS Status;
1865 HDA_CODEC_DEV *HdaCodecDev;
1866
1867 // Get codec device.
1868 Status = gBS->OpenProtocol (
1869 ControllerHandle,
1870 &gEfiCallerIdGuid,
1871 (VOID **)&HdaCodecDev,
1872 This->DriverBindingHandle,
1873 ControllerHandle,
1874 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1875 );
1876 if (!(EFI_ERROR (Status))) {
1877 // Ensure codec device is valid.
1878 if (HdaCodecDev->Signature != HDA_CODEC_PRIVATE_DATA_SIGNATURE) {
1879 return EFI_INVALID_PARAMETER;
1880 }
1881
1882 // Cleanup codec.
1883 HdaCodecCleanup (HdaCodecDev);
1884 }
1885
1886 // Close protocols.
1887 gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle);
1888 gBS->CloseProtocol (ControllerHandle, &gEfiHdaIoProtocolGuid, This->DriverBindingHandle, ControllerHandle);
1889 return EFI_SUCCESS;
1890}
#define EFI_AUDIO_IO_PROTOCOL_REVISION
Definition AudioIo.h:40
EFI_GUID gEfiAudioIoProtocolGuid
EFI_STATUS EFIAPI HdaCodecInstallProtocols(IN HDA_CODEC_DEV *HdaCodecDev)
Definition HdaCodec.c:1078
UINTN gForcedCodec
Definition HdaCodec.c:46
EFI_STATUS EFIAPI HdaCodecGetSupportedPcmRates(IN HDA_WIDGET_DEV *HdaPinWidget, OUT UINT32 *SupportedRates)
Definition HdaCodec.c:1183
EFI_STATUS EFIAPI HdaCodecProbeFuncGroup(IN HDA_FUNC_GROUP *FuncGroup)
Definition HdaCodec.c:558
EFI_STATUS EFIAPI HdaCodecProbeWidget(IN HDA_WIDGET_DEV *HdaWidget)
Definition HdaCodec.c:53
UINTN gCodecSetupDelay
Definition HdaCodec.c:40
VOID EFIAPI HdaCodecCleanup(IN HDA_CODEC_DEV *HdaCodecDev)
Definition HdaCodec.c:1612
BOOLEAN gCodecUseConnNoneNode
Definition HdaCodec.c:49
EFI_STATUS EFIAPI HdaCodecDisableWidgetPath(IN HDA_WIDGET_DEV *HdaWidget)
Definition HdaCodec.c:1228
EFI_STATUS EFIAPI HdaCodecProbeCodec(IN HDA_CODEC_DEV *HdaCodecDev)
Definition HdaCodec.c:779
EFI_STATUS EFIAPI HdaCodecFindUpstreamOutput(IN HDA_WIDGET_DEV *HdaWidget, IN UINT8 Level)
Definition HdaCodec.c:872
EFI_STATUS EFIAPI HdaCodecGetOutputDac(IN HDA_WIDGET_DEV *HdaWidget, OUT HDA_WIDGET_DEV **HdaOutputWidget)
Definition HdaCodec.c:1153
EFI_STATUS EFIAPI HdaCodecEnableWidgetPath(IN HDA_WIDGET_DEV *HdaWidget, IN INT8 Gain, IN UINT8 StreamId, IN UINT16 StreamFormat)
Definition HdaCodec.c:1344
EFI_STATUS EFIAPI HdaCodecDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
Definition HdaCodec.c:1717
EFI_STATUS EFIAPI HdaCodecDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
Definition HdaCodec.c:1765
UINTN gGpioSetupStageMask
Definition HdaCodec.c:34
EFI_STATUS EFIAPI HdaCodecWidgetRawGainToDecibels(IN HDA_WIDGET_DEV *HdaWidget, IN UINT8 GainParam, OUT INT8 *Gain)
Definition HdaCodec.c:1288
UINTN gGpioPinMask
Definition HdaCodec.c:37
BOOLEAN gUseForcedCodec
Definition HdaCodec.c:43
EFI_STATUS EFIAPI HdaCodecDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL)
Definition HdaCodec.c:1854
EFI_STATUS EFIAPI HdaCodecParsePorts(IN HDA_CODEC_DEV *HdaCodecDev)
Definition HdaCodec.c:924
#define GPIO_SETUP_STAGE_NONE
Definition HdaCodec.h:374
EFI_STATUS EFIAPI HdaCodecAudioIoSetupPlayback(IN EFI_AUDIO_IO_PROTOCOL *This, IN UINT64 OutputIndexMask, IN INT8 Gain, IN EFI_AUDIO_IO_PROTOCOL_FREQ Freq, IN EFI_AUDIO_IO_PROTOCOL_BITS Bits, IN UINT8 Channels, IN UINTN PlaybackDelay)
EFI_STATUS EFIAPI HdaCodecInfoGetCodecName(IN EFI_HDA_CODEC_INFO_PROTOCOL *This, OUT CONST CHAR16 **CodecName)
EFI_STATUS EFIAPI HdaCodecInfoGetWidgets(IN EFI_HDA_CODEC_INFO_PROTOCOL *This, OUT HDA_WIDGET **Widgets, OUT UINTN *WidgetCount)
EFI_STATUS EFIAPI HdaCodecAudioIoStartPlaybackAsync(IN EFI_AUDIO_IO_PROTOCOL *This, IN VOID *Data, IN UINTN DataLength, IN UINTN Position OPTIONAL, IN EFI_AUDIO_IO_CALLBACK Callback OPTIONAL, IN VOID *Context OPTIONAL)
EFI_STATUS EFIAPI HdaCodecInfoGetAudioFuncId(IN EFI_HDA_CODEC_INFO_PROTOCOL *This, OUT UINT8 *AudioFuncId, OUT BOOLEAN *UnsolCapable)
EFI_STATUS EFIAPI HdaCodecAudioIoStartPlayback(IN EFI_AUDIO_IO_PROTOCOL *This, IN VOID *Data, IN UINTN DataLength, IN UINTN Position OPTIONAL)
#define HDA_CODEC_PRIVATE_DATA_SIGNATURE
Definition HdaCodec.h:35
EFI_STATUS EFIAPI HdaCodecInfoGetRevisionId(IN EFI_HDA_CODEC_INFO_PROTOCOL *This, OUT UINT32 *RevisionId)
EFI_STATUS EFIAPI HdaCodecInfoFreeWidgetsBuffer(IN HDA_WIDGET *Widgets, IN UINTN WidgetCount)
EFI_STATUS EFIAPI HdaCodecInfoGetVendorId(IN EFI_HDA_CODEC_INFO_PROTOCOL *This, OUT UINT32 *VendorId)
EFI_STATUS EFIAPI HdaCodecAudioIoGetOutputs(IN EFI_AUDIO_IO_PROTOCOL *This, OUT EFI_AUDIO_IO_PROTOCOL_PORT **OutputPorts, OUT UINTN *OutputPortsCount)
EFI_STATUS EFIAPI HdaCodecInfoGetAddress(IN EFI_HDA_CODEC_INFO_PROTOCOL *This, OUT UINT8 *Address)
EFI_STATUS EFIAPI HdaCodecInfoGetDefaultRatesFormats(IN EFI_HDA_CODEC_INFO_PROTOCOL *This, OUT UINT32 *Rates, OUT UINT32 *Formats)
EFI_STATUS EFIAPI HdaCodecInfoGetDefaultAmpCaps(IN EFI_HDA_CODEC_INFO_PROTOCOL *This, OUT UINT32 *AmpInCaps, OUT UINT32 *AmpOutCaps)
EFI_STATUS EFIAPI HdaCodecAudioIoRawGainToDecibels(IN EFI_AUDIO_IO_PROTOCOL *This, IN UINT64 OutputIndexMask, IN UINT8 GainParam, OUT INT8 *Gain)
#define GPIO_PIN_MASK_AUTO
Auto: use all reported available pins.
Definition HdaCodec.h:383
EFI_STATUS EFIAPI HdaCodecAudioIoStopPlayback(IN EFI_AUDIO_IO_PROTOCOL *This)
EFI_GUID gEfiHdaCodecInfoProtocolGuid
EFI_GUID gEfiHdaIoProtocolGuid
#define HDA_VERB_GET_CONFIGURATION_DEFAULT_DEVICE(a)
Definition HdaVerbs.h:275
#define HDA_PARAMETER_AMP_CAPS_INPUT
Definition HdaVerbs.h:476
#define HDA_CONFIG_DEFAULT_DEVICE_SPEAKER
Definition HdaVerbs.h:278
#define HDA_PARAMETER_WIDGET_CAPS_DIGITAL
Definition HdaVerbs.h:410
#define HDA_VERB_GET_PARAMETER
Definition HdaVerbs.h:363
#define HDA_PARAMETER_PIN_CAPS_EAPD
Definition HdaVerbs.h:471
#define HDA_PIN_WIDGET_CONTROL_VREF_50
50%
Definition HdaVerbs.h:113
#define HDA_PARAMETER_SUPPORTED_STREAM_FORMATS_PCM
Definition HdaVerbs.h:451
#define HDA_CONFIG_DEFAULT_DEVICE_LINE_OUT
Definition HdaVerbs.h:277
#define HDA_PARAMETER_WIDGET_CAPS_UNSOL_CAPABLE
Definition HdaVerbs.h:408
#define HDA_PARAMETER_WIDGET_CAPS_AMP_OVERRIDE
Definition HdaVerbs.h:404
#define HDA_PARAMETER_WIDGET_CAPS_POWER_CNTRL
Definition HdaVerbs.h:411
#define HDA_VERB_SET_DIGITAL_CONV_CONTROL1
Definition HdaVerbs.h:133
#define HDA_CODEC_VERB(Verb, Payload)
Definition HdaVerbs.h:32
#define HDA_PARAMETER_SUPPORTED_STREAM_FORMATS
Definition HdaVerbs.h:450
#define HDA_PARAMETER_PIN_CAPS_VREF(a)
Definition HdaVerbs.h:465
#define HDA_PARAMETER_PIN_CAPS_VREF_100
100%
Definition HdaVerbs.h:470
#define HDA_VERB_SET_CONVERTER_STREAM_CHANNEL
Definition HdaVerbs.h:103
#define HDA_PARAMETER_SUPPORTED_PCM_SIZE_RATES
Definition HdaVerbs.h:430
#define HDA_VERB_GET_POWER_STATE
Definition HdaVerbs.h:98
#define HDA_VERB_SET_AMP_GAIN_MUTE
Definition HdaVerbs.h:60
#define HDA_PARAMETER_SUBNODE_COUNT_START(a)
Definition HdaVerbs.h:384
#define HDA_NID_ROOT
Definition HdaVerbs.h:29
#define HDA_PARAMETER_WIDGET_CAPS_FORMAT_OVERRIDE
Definition HdaVerbs.h:405
#define HDA_VERB_GET_CONN_LIST_ENTRY_LONG(a, i)
Definition HdaVerbs.h:80
#define HDA_WIDGET_TYPE_PIN_COMPLEX
Definition HdaVerbs.h:423
#define HDA_CONFIG_DEFAULT_DEVICE_SPDIF_OUT
Definition HdaVerbs.h:281
#define HDA_VERB_SET_PIN_WIDGET_CONTROL
Definition HdaVerbs.h:110
#define HDA_VERB_SET_AMP_GAIN_MUTE_PAYLOAD(index, gain, mute, right, left, in, out)
Definition HdaVerbs.h:61
#define HDA_PARAMETER_WIDGET_CAPS_IN_AMP
Definition HdaVerbs.h:402
#define HDA_PARAMETER_FUNC_GROUP_TYPE
Definition HdaVerbs.h:387
#define HDA_VERB_GET_CONVERTER_STREAM_CHANNEL
Definition HdaVerbs.h:102
#define HDA_PIN_WIDGET_CONTROL_VREF_80
80%
Definition HdaVerbs.h:115
#define HDA_PARAMETER_PIN_CAPS_OUTPUT
Definition HdaVerbs.h:461
#define HDA_EAPD_BTL_ENABLE_EAPD
Definition HdaVerbs.h:162
#define HDA_PARAMETER_AMP_CAPS_NUM_STEPS(a)
Definition HdaVerbs.h:479
#define HDA_PARAMETER_VENDOR_ID_DEV(a)
Definition HdaVerbs.h:371
#define HDA_PARAMETER_SUPPORTED_POWER_STATES
Definition HdaVerbs.h:489
#define HDA_PARAMETER_AMP_CAPS_STEP_SIZE(a)
Definition HdaVerbs.h:480
#define HDA_CONFIG_DEFAULT_PORT_CONN_NONE
Definition HdaVerbs.h:315
#define HDA_PARAMETER_AMP_CAPS_OUTPUT
Definition HdaVerbs.h:477
#define HDA_PARAMETER_WIDGET_CAPS_CONN_LIST
Definition HdaVerbs.h:409
#define HDA_PARAMETER_CONN_LIST_LENGTH_LEN(a)
Definition HdaVerbs.h:485
#define HDA_VERB_SET_EAPD_BTL_ENABLE
Definition HdaVerbs.h:160
#define HDA_VERB_GET_VOLUME_KNOB
Definition HdaVerbs.h:166
#define HDA_VERB_GET_CONVERTER_CHANNEL_COUNT
Definition HdaVerbs.h:330
#define HDA_VERB_GET_CONN_LIST_ENTRY_SHORT_VALUE(a)
Definition HdaVerbs.h:83
#define HDA_VERB_SET_CONVERTER_STREAM_PAYLOAD(c, s)
Definition HdaVerbs.h:106
#define HDA_VERB_GET_CONFIGURATION_DEFAULT
Definition HdaVerbs.h:224
#define HDA_VERB_GET_CONN_LIST_ENTRY_SHORT(a, i)
Definition HdaVerbs.h:79
#define HDA_VERB_GET_CONFIGURATION_DEFAULT_ASSOCIATION(a)
Definition HdaVerbs.h:235
#define HDA_PARAMETER_CONN_LIST_LENGTH
Definition HdaVerbs.h:484
#define HDA_PARAMETER_SUBNODE_COUNT_TOTAL(a)
Definition HdaVerbs.h:383
#define HDA_PARAMETER_AMP_CAPS_OFFSET(a)
Definition HdaVerbs.h:478
#define HDA_VERB_GET_CONN_LIST_ENTRY_SHORT_IS_RANGE
Definition HdaVerbs.h:81
#define HDA_VERB_GET_EAPD_BTL_ENABLE
Definition HdaVerbs.h:159
#define HDA_PARAMETER_VOLUME_KNOB_CAPS
Definition HdaVerbs.h:513
#define HDA_VERB_GET_AMP_GAIN_MUTE_PAYLOAD(index, left, out)
Definition HdaVerbs.h:55
#define HDA_VERB_SET_CONN_SELECT_CONTROL
Definition HdaVerbs.h:75
#define HDA_PARAMETER_VENDOR_ID_VEN(a)
Definition HdaVerbs.h:372
#define HDA_WIDGET_TYPE_OUTPUT
Definition HdaVerbs.h:419
#define HDA_WIDGET_TYPE_VOLUME_KNOB
Definition HdaVerbs.h:425
#define HDA_PARAMETER_FUNC_GROUP_TYPE_NODETYPE(a)
Definition HdaVerbs.h:388
#define HDA_PARAMETER_FUNC_GROUP_TYPE_UNSOL
Definition HdaVerbs.h:389
#define HDA_VERB_SET_POWER_STATE
Definition HdaVerbs.h:99
#define HDA_PARAMETER_CONN_LIST_LENGTH_LONG
Definition HdaVerbs.h:486
#define HDA_VERB_GET_CONN_LIST_ENTRY_LONG_VALUE(a)
Definition HdaVerbs.h:84
#define HDA_VERB_GET_AMP_GAIN_MUTE
Definition HdaVerbs.h:54
#define HDA_PIN_WIDGET_CONTROL_VREF_100
100%
Definition HdaVerbs.h:116
#define HDA_PARAMETER_WIDGET_CAPS
Definition HdaVerbs.h:400
#define HDA_PARAMETER_VENDOR_ID
Definition HdaVerbs.h:370
#define HDA_PARAMETER_PIN_CAPS_VREF_80
80%
Definition HdaVerbs.h:469
#define HDA_FUNC_GROUP_TYPE_AUDIO
Definition HdaVerbs.h:390
#define HDA_VERB_GET_PIN_WIDGET_CONTROL
Definition HdaVerbs.h:109
#define HDA_VERB_SET_PIN_WIDGET_CONTROL_PAYLOAD(vref, in, out, hp)
Definition HdaVerbs.h:120
#define HDA_VERB_GET_CONN_LIST_ENTRY
Definition HdaVerbs.h:78
#define HDA_PARAMETER_REVISION_ID
Definition HdaVerbs.h:375
#define HDA_CONFIG_DEFAULT_DEVICE_OTHER_DIGITAL_OUT
Definition HdaVerbs.h:282
#define HDA_PARAMETER_SUBNODE_COUNT
Definition HdaVerbs.h:382
#define HDA_VERB_GET_UNSOL_RESPONSE
Definition HdaVerbs.h:127
#define HDA_PIN_WIDGET_CONTROL_VREF_HIZ
Hi-Z.
Definition HdaVerbs.h:112
#define HDA_PARAMETER_WIDGET_CAPS_TYPE(a)
Definition HdaVerbs.h:416
#define HDA_PARAMETER_PIN_CAPS_VREF_50
50%
Definition HdaVerbs.h:467
#define HDA_CONFIG_DEFAULT_DEVICE_HEADPHONE_OUT
Definition HdaVerbs.h:279
#define HDA_VERB_GET_CONFIGURATION_DEFAULT_PORT_CONN(a)
Definition HdaVerbs.h:312
#define HDA_PARAMETER_GPIO_COUNT
Definition HdaVerbs.h:505
#define HDA_VERB_SET_CONVERTER_FORMAT
Definition HdaVerbs.h:38
#define HDA_PARAMETER_AMP_CAPS_MUTE
Definition HdaVerbs.h:481
#define HDA_DIGITAL_CONV_CONTROL_DIGEN
Definition HdaVerbs.h:137
#define HDA_VERB_SET_ASP_MAPPING
Definition HdaVerbs.h:357
#define HDA_PARAMETER_FUNC_GROUP_CAPS
Definition HdaVerbs.h:394
#define HDA_VERB_GET_CONN_LIST_ENTRY_LONG_IS_RANGE
Definition HdaVerbs.h:82
#define HDA_VERB_GET_CONVERTER_FORMAT
Definition HdaVerbs.h:37
#define HDA_WIDGET_TYPE_INPUT
Definition HdaVerbs.h:420
#define HDA_PARAMETER_WIDGET_CAPS_OUT_AMP
Definition HdaVerbs.h:403
#define HDA_PARAMETER_PIN_CAPS
Definition HdaVerbs.h:456
EFI_BOOT_SERVICES * gBS
CONST CHAR8 * OcHdaCodecGetName(IN UINT32 CodecId, IN UINT16 RevisionId)
#define MS_TO_MICROSECONDS(x)
Definition OcMiscLib.h:31
CHAR16 * AsciiStrCopyToUnicode(IN CONST CHAR8 *String, IN UINTN Length)
Definition OcAsciiLib.c:119
EFI_GUID gEfiDevicePathProtocolGuid
HDA_CODEC_DEV * HdaCodecDev
Definition HdaCodec.h:156
EFI_AUDIO_IO_PROTOCOL AudioIo
Definition HdaCodec.h:151
UINTN Signature
Definition HdaCodec.h:106
EFI_HANDLE ControllerHandle
Definition HdaCodec.h:111
EFI_HDA_IO_PROTOCOL * HdaIo
Definition HdaCodec.h:109
EFI_DEVICE_PATH_PROTOCOL * DevicePath
Definition HdaCodec.h:110
HDA_CODEC_DEV * HdaCodecDev
Definition HdaCodec.h:140
EFI_HDA_CODEC_INFO_PROTOCOL HdaCodecInfo
Definition HdaCodec.h:139
UINT32 AmpOutCapabilities
Definition HdaCodec.h:96
UINT8 WidgetsCount
Definition HdaCodec.h:101
HDA_WIDGET_DEV * Widgets
Definition HdaCodec.h:100
UINT32 SupportedFormats
Definition HdaCodec.h:94
UINT32 SupportedPcmRates
Definition HdaCodec.h:93
UINT8 UpstreamIndex
Definition HdaCodec.h:52
UINT8 * AmpInRightDefaultGainMute
Definition HdaCodec.h:63
UINT32 AmpOutCapabilities
Definition HdaCodec.h:61
UINT32 ConnectionCount
Definition HdaCodec.h:50
HDA_FUNC_GROUP * FuncGroup
Definition HdaCodec.h:38
UINT32 DefaultConfiguration
Definition HdaCodec.h:78
UINT16 * Connections
Definition HdaCodec.h:48
HDA_WIDGET_DEV ** WidgetConnections
Definition HdaCodec.h:49
UINT8 * AmpInLeftDefaultGainMute
Definition HdaCodec.h:62
BOOLEAN AmpOverride
Definition HdaCodec.h:59
UINT32 SupportedFormats
Definition HdaCodec.h:69
UINT32 PinCapabilities
Definition HdaCodec.h:75
UINT32 Capabilities
Definition HdaCodec.h:43
UINT32 SupportedPcmRates
Definition HdaCodec.h:68
EFI_AUDIO_IO_START_PLAYBACK StartPlayback
Definition AudioIo.h:283
EFI_AUDIO_IO_STOP_PLAYBACK StopPlayback
Definition AudioIo.h:285
EFI_AUDIO_IO_START_PLAYBACK_ASYNC StartPlaybackAsync
Definition AudioIo.h:284
EFI_AUDIO_IO_GET_OUTPUTS GetOutputs
Definition AudioIo.h:280
EFI_AUDIO_IO_SETUP_PLAYBACK SetupPlayback
Definition AudioIo.h:282
EFI_AUDIO_IO_RAW_GAIN_TO_DECIBELS RawGainToDecibels
Definition AudioIo.h:281
EFI_HDA_CODEC_INFO_GET_NAME GetName
EFI_HDA_CODEC_INFO_GET_VENDOR_ID GetVendorId
EFI_HDA_CODEC_INFO_GET_DEFAULT_RATES_FORMATS GetDefaultRatesFormats
EFI_HDA_CODEC_INFO_GET_AUDIO_FUNC_ID GetAudioFuncId
EFI_HDA_CODEC_INFO_GET_WIDGETS GetWidgets
EFI_HDA_CODEC_INFO_GET_REVISION_ID GetRevisionId
EFI_HDA_CODEC_INFO_GET_ADDRESS GetAddress
EFI_HDA_CODEC_INFO_FREE_WIDGETS_BUFFER FreeWidgetsBuffer
EFI_HDA_CODEC_INFO_GET_DEFAULT_AMP_CAPS GetDefaultAmpCaps
EFI_HDA_IO_GET_ADDRESS GetAddress
Definition HdaIo.h:177
EFI_HDA_IO_SEND_COMMAND SendCommand
Definition HdaIo.h:178