1 /*
2 * Copyright 2007-2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
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
9 */
10
11
12 #include "driver.h"
13 #include "hda_codec_defs.h"
14
15
16 #undef TRACE
17 #define TRACE_CODEC
18 #ifdef TRACE_CODEC
19 # define TRACE(a...) dprintf("hda: " a)
20 #else
21 # define TRACE(a...)
22 #endif
23 #define ERROR(a...) dprintf("hda: " a)
24
25
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 \
43 | HDA_QUIRK_IVREF100)
44 #define HDA_QUIRK_OVREF (HDA_QUIRK_OVREF50 | HDA_QUIRK_OVREF80 \
45 | HDA_QUIRK_OVREF100)
46
47
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
54
55
56 static const char* kPortConnector[] = {
57 "Jack", "None", "Fixed", "Dual"
58 };
59
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"
64 };
65
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"
70 };
71
72 static const char* kJackColor[] = {
73 "N/A", "Black", "Grey", "Blue", "Green", "Red", "Orange", "Yellow",
74 "Purple", "Pink", "-", "-", "-", "-", "White", "Other"
75 };
76
77 static const struct {
78 uint32 subsystem_vendor_id, subsystem_id;
79 uint32 codec_vendor_id, codec_id;
80 uint32 quirks, nonquirks;
81 } kCodecQuirks[] = {
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, 0x00a0, REALTEK_VENDORID, 0x0885,
93 HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF80, 0}, // iMac 8,1, Macbook Pro 3,1
94 { 0x106b, 0x00a1, REALTEK_VENDORID, 0x0885,
95 HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF50, 0}, // MacBook
96 { 0x106b, 0x00a3, REALTEK_VENDORID, 0x0885,
97 HDA_QUIRK_GPIO0, 0}, // MacBook
98 { 0x106b, 0x7200, CIRRUSLOGIC_VENDORID, 0x4208,
99 HDA_QUIRK_GPIO0, 0}, // MacBookAir 6,2
100 { HDA_ALL, HDA_ALL, IDT_VENDORID, 0x76b2, HDA_QUIRK_GPIO0, 0},
101 };
102
103
104 static const char*
get_widget_type_name(hda_widget_type type)105 get_widget_type_name(hda_widget_type type)
106 {
107 switch (type) {
108 case WT_AUDIO_OUTPUT:
109 return "Audio output";
110 case WT_AUDIO_INPUT:
111 return "Audio input";
112 case WT_AUDIO_MIXER:
113 return "Audio mixer";
114 case WT_AUDIO_SELECTOR:
115 return "Audio selector";
116 case WT_PIN_COMPLEX:
117 return "Pin complex";
118 case WT_POWER:
119 return "Power";
120 case WT_VOLUME_KNOB:
121 return "Volume knob";
122 case WT_BEEP_GENERATOR:
123 return "Beep generator";
124 case WT_VENDOR_DEFINED:
125 return "Vendor defined";
126 default:
127 return "Unknown";
128 }
129 }
130
131
132 const char*
get_widget_location(uint32 location)133 get_widget_location(uint32 location)
134 {
135 switch (location >> 4) {
136 case 0:
137 case 2:
138 switch (location & 0xf) {
139 case 2:
140 return "Front";
141 case 3:
142 return "Left";
143 case 4:
144 return "Right";
145 case 5:
146 return "Top";
147 case 6:
148 return "Bottom";
149 case 7:
150 return "Rear panel";
151 case 8:
152 return "Drive bay";
153 case 0:
154 case 1:
155 default:
156 return NULL;
157 }
158 case 1:
159 switch (location & 0xf) {
160 case 7:
161 return "Riser";
162 case 8:
163 return "HDMI";
164 default:
165 return NULL;
166 }
167 case 3:
168 switch (location & 0xf) {
169 case 6:
170 return "Bottom";
171 case 7:
172 return "Inside lid";
173 case 8:
174 return "Outside lid";
175 default:
176 return NULL;
177 }
178 }
179 return NULL;
180 }
181
182
183 static void
dump_widget_audio_capabilities(uint32 capabilities)184 dump_widget_audio_capabilities(uint32 capabilities)
185 {
186 static const struct {
187 uint32 flag;
188 const char* name;
189 } kFlags[] = {
190 {AUDIO_CAP_CP_CAPS, "CP caps"},
191 {AUDIO_CAP_LEFT_RIGHT_SWAP, "L-R swap"},
192 {AUDIO_CAP_POWER_CONTROL, "Power"},
193 {AUDIO_CAP_DIGITAL, "Digital"},
194 {AUDIO_CAP_CONNECTION_LIST, "Conn. list"},
195 {AUDIO_CAP_UNSOLICITED_RESPONSES, "Unsol. responses"},
196 {AUDIO_CAP_PROCESSING_CONTROLS, "Proc widget"},
197 {AUDIO_CAP_STRIPE, "Stripe"},
198 {AUDIO_CAP_FORMAT_OVERRIDE, "Format override"},
199 {AUDIO_CAP_AMPLIFIER_OVERRIDE, "Amplifier override"},
200 {AUDIO_CAP_OUTPUT_AMPLIFIER, "Out amplifier"},
201 {AUDIO_CAP_INPUT_AMPLIFIER, "In amplifier"},
202 {AUDIO_CAP_STEREO, "Stereo"},
203 };
204
205 char buffer[256];
206 int offset = 0;
207
208 for (uint32 j = 0; j < sizeof(kFlags) / sizeof(kFlags[0]); j++) {
209 if ((capabilities & kFlags[j].flag) != 0)
210 offset += sprintf(buffer + offset, "[%s] ", kFlags[j].name);
211 }
212
213 if (offset != 0)
214 TRACE("\t%s\n", buffer);
215 }
216
217
218 static void
dump_widget_inputs(hda_widget & widget)219 dump_widget_inputs(hda_widget& widget)
220 {
221 // dump connections
222
223 char buffer[256];
224 int offset = 0;
225
226 for (uint32 i = 0; i < widget.num_inputs; i++) {
227 int32 input = widget.inputs[i];
228
229 if ((int32)i != widget.active_input)
230 offset += sprintf(buffer + offset, "%" B_PRId32 " ", input);
231 else
232 offset += sprintf(buffer + offset, "<%" B_PRId32 "> ", input);
233 }
234
235 if (offset != 0)
236 TRACE("\tInputs: %s\n", buffer);
237 }
238
239
240 static void
dump_widget_amplifier_capabilities(hda_widget & widget,bool input)241 dump_widget_amplifier_capabilities(hda_widget& widget, bool input)
242 {
243 uint32 capabilities;
244 if (input)
245 capabilities = widget.capabilities.input_amplifier;
246 else
247 capabilities = widget.capabilities.output_amplifier;
248
249 if (capabilities == 0)
250 return;
251
252 TRACE("\t%s Amp: %sstep size: %f dB, # steps: %" B_PRIu32 ", "
253 "offset to 0 dB: %" B_PRIu32 "\n",
254 input ? "In" : "Out",
255 (capabilities & AMP_CAP_MUTE) != 0 ? "supports mute, " : "",
256 AMP_CAP_STEP_SIZE(capabilities),
257 AMP_CAP_NUM_STEPS(capabilities),
258 AMP_CAP_OFFSET(capabilities));
259 }
260
261
262 static void
dump_widget_pm_support(hda_widget & widget)263 dump_widget_pm_support(hda_widget& widget)
264 {
265 TRACE("\tSupported power states: %s%s%s%s%s%s%s%s\n",
266 widget.pm & POWER_STATE_D0 ? "D0 " : "",
267 widget.pm & POWER_STATE_D1 ? "D1 " : "",
268 widget.pm & POWER_STATE_D2 ? "D2 " : "",
269 widget.pm & POWER_STATE_D3 ? "D3 " : "",
270 widget.pm & POWER_STATE_D3COLD ? "D3COLD " : "",
271 widget.pm & POWER_STATE_S3D3COLD ? "S3D3COLD " : "",
272 widget.pm & POWER_STATE_CLKSTOP ? "CLKSTOP " : "",
273 widget.pm & POWER_STATE_EPSS ? "EPSS " : "");
274 }
275
276
277 static void
dump_widget_stream_support(hda_widget & widget)278 dump_widget_stream_support(hda_widget& widget)
279 {
280 TRACE("\tSupported formats: %s%s%s%s%s%s%s%s%s\n",
281 widget.d.io.formats & B_FMT_8BIT_S ? "8bits " : "",
282 widget.d.io.formats & B_FMT_16BIT ? "16bits " : "",
283 widget.d.io.formats & B_FMT_20BIT ? "20bits " : "",
284 widget.d.io.formats & B_FMT_24BIT ? "24bits " : "",
285 widget.d.io.formats & B_FMT_32BIT ? "32bits " : "",
286 widget.d.io.formats & B_FMT_FLOAT ? "float " : "",
287 widget.d.io.formats & B_FMT_DOUBLE ? "double " : "",
288 widget.d.io.formats & B_FMT_EXTENDED ? "extended " : "",
289 widget.d.io.formats & B_FMT_BITSTREAM ? "bitstream " : "");
290 TRACE("\tSupported rates: %s%s%s%s%s%s%s%s%s%s%s%s\n",
291 widget.d.io.rates & B_SR_8000 ? "8khz " : "",
292 widget.d.io.rates & B_SR_11025 ? "11khz " : "",
293 widget.d.io.rates & B_SR_16000 ? "16khz " : "",
294 widget.d.io.rates & B_SR_22050 ? "22khz " : "",
295 widget.d.io.rates & B_SR_32000 ? "32khz " : "",
296 widget.d.io.rates & B_SR_44100 ? "44khz " : "",
297 widget.d.io.rates & B_SR_48000 ? "48khz " : "",
298 widget.d.io.rates & B_SR_88200 ? "88khz " : "",
299 widget.d.io.rates & B_SR_96000 ? "96khz " : "",
300 widget.d.io.rates & B_SR_176400 ? "176khz " : "",
301 widget.d.io.rates & B_SR_192000 ? "192khz " : "",
302 widget.d.io.rates & B_SR_384000 ? "384khz " : "");
303
304 }
305
306
307 static void
dump_pin_complex_capabilities(hda_widget & widget)308 dump_pin_complex_capabilities(hda_widget& widget)
309 {
310 TRACE("\t%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
311 widget.d.pin.capabilities & PIN_CAP_IMP_SENSE ? "[Imp Sense] " : "",
312 widget.d.pin.capabilities & PIN_CAP_TRIGGER_REQ ? "[Trigger Req]" : "",
313 widget.d.pin.capabilities & PIN_CAP_PRES_DETECT ? "[Pres Detect]" : "",
314 widget.d.pin.capabilities & PIN_CAP_HP_DRIVE ? "[HP Drive]" : "",
315 widget.d.pin.capabilities & PIN_CAP_OUTPUT ? "[Output]" : "",
316 widget.d.pin.capabilities & PIN_CAP_INPUT ? "[Input]" : "",
317 widget.d.pin.capabilities & PIN_CAP_BALANCE ? "[Balance]" : "",
318 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_HIZ ? "[VRef HIZ]" : "",
319 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_50 ? "[VRef 50]" : "",
320 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_GROUND ? "[VRef Gr]" : "",
321 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_80 ? "[VRef 80]" : "",
322 widget.d.pin.capabilities & PIN_CAP_VREF_CTRL_100 ? "[VRef 100]" : "",
323 widget.d.pin.capabilities & PIN_CAP_EAPD_CAP ? "[EAPD]" : "");
324 }
325
326
327 static void
dump_audiogroup_widgets(hda_audio_group * audioGroup)328 dump_audiogroup_widgets(hda_audio_group* audioGroup)
329 {
330 TRACE("\tAudiogroup:\n");
331 // Iterate over all widgets and collect info
332 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
333 hda_widget& widget = audioGroup->widgets[i];
334 uint32 nodeID = audioGroup->widget_start + i;
335
336 TRACE("%" B_PRIu32 ": %s\n", nodeID, get_widget_type_name(widget.type));
337
338 switch (widget.type) {
339 case WT_AUDIO_OUTPUT:
340 case WT_AUDIO_INPUT:
341 break;
342
343 case WT_PIN_COMPLEX:
344 dump_pin_complex_capabilities(widget);
345 break;
346
347 default:
348 break;
349 }
350
351 dump_widget_pm_support(widget);
352 dump_widget_audio_capabilities(widget.capabilities.audio);
353 dump_widget_amplifier_capabilities(widget, true);
354 dump_widget_amplifier_capabilities(widget, false);
355 dump_widget_inputs(widget);
356 }
357 }
358
359
360 // #pragma mark -
361
362
363 static void
hda_codec_get_quirks(hda_codec * codec)364 hda_codec_get_quirks(hda_codec* codec)
365 {
366 codec->quirks = 0;
367
368 uint32 subSystemID = codec->subsystem_id & 0xffff;
369 uint32 subSystemVendorID = codec->subsystem_id >> 16;
370
371 for (uint32 i = 0;
372 i < (sizeof(kCodecQuirks) / sizeof(kCodecQuirks[0])); i++) {
373 if (kCodecQuirks[i].subsystem_id != HDA_ALL
374 && kCodecQuirks[i].subsystem_id != subSystemID)
375 continue;
376 if (kCodecQuirks[i].subsystem_vendor_id != HDA_ALL
377 && kCodecQuirks[i].subsystem_vendor_id != subSystemVendorID)
378 continue;
379 if (kCodecQuirks[i].codec_vendor_id != HDA_ALL
380 && kCodecQuirks[i].codec_vendor_id != codec->vendor_id)
381 continue;
382 if (kCodecQuirks[i].codec_id != HDA_ALL
383 && kCodecQuirks[i].codec_id != codec->product_id)
384 continue;
385
386 codec->quirks |= kCodecQuirks[i].quirks;
387 codec->quirks &= ~kCodecQuirks[i].nonquirks;
388 }
389 }
390
391
392 static status_t
hda_get_pm_support(hda_codec * codec,uint32 nodeID,uint32 * pm)393 hda_get_pm_support(hda_codec* codec, uint32 nodeID, uint32* pm)
394 {
395 corb_t verb = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER,
396 PID_POWERSTATE_SUPPORT);
397
398 uint32 response;
399 status_t status = hda_send_verbs(codec, &verb, &response, 1);
400 if (status == B_OK)
401 *pm = response & 0xf;
402
403 return status;
404 }
405
406
407 static status_t
hda_get_stream_support(hda_codec * codec,uint32 nodeID,uint32 * formats,uint32 * rates)408 hda_get_stream_support(hda_codec* codec, uint32 nodeID, uint32* formats,
409 uint32* rates)
410 {
411 corb_t verbs[2];
412 uint32 resp[2];
413 status_t status;
414
415 verbs[0] = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER,
416 PID_STREAM_SUPPORT);
417 verbs[1] = MAKE_VERB(codec->addr, nodeID, VID_GET_PARAMETER,
418 PID_PCM_SUPPORT);
419
420 status = hda_send_verbs(codec, verbs, resp, 2);
421 if (status != B_OK)
422 return status;
423
424 *formats = 0;
425 *rates = 0;
426
427 if ((resp[0] & (STREAM_FLOAT | STREAM_PCM)) != 0) {
428 if (resp[1] & (1 << 0))
429 *rates |= B_SR_8000;
430 if (resp[1] & (1 << 1))
431 *rates |= B_SR_11025;
432 if (resp[1] & (1 << 2))
433 *rates |= B_SR_16000;
434 if (resp[1] & (1 << 3))
435 *rates |= B_SR_22050;
436 if (resp[1] & (1 << 4))
437 *rates |= B_SR_32000;
438 if (resp[1] & (1 << 5))
439 *rates |= B_SR_44100;
440 if (resp[1] & (1 << 6))
441 *rates |= B_SR_48000;
442 if (resp[1] & (1 << 7))
443 *rates |= B_SR_88200;
444 if (resp[1] & (1 << 8))
445 *rates |= B_SR_96000;
446 if (resp[1] & (1 << 9))
447 *rates |= B_SR_176400;
448 if (resp[1] & (1 << 10))
449 *rates |= B_SR_192000;
450 if (resp[1] & (1 << 11))
451 *rates |= B_SR_384000;
452
453 if (resp[1] & PCM_8_BIT)
454 *formats |= B_FMT_8BIT_S;
455 if (resp[1] & PCM_16_BIT)
456 *formats |= B_FMT_16BIT;
457 if (resp[1] & PCM_20_BIT)
458 *formats |= B_FMT_20BIT;
459 if (resp[1] & PCM_24_BIT)
460 *formats |= B_FMT_24BIT;
461 if (resp[1] & PCM_32_BIT)
462 *formats |= B_FMT_32BIT;
463 }
464 if ((resp[0] & STREAM_FLOAT) != 0)
465 *formats |= B_FMT_FLOAT;
466 if ((resp[0] & STREAM_AC3) != 0) {
467 *formats |= B_FMT_BITSTREAM;
468 }
469
470 return B_OK;
471 }
472
473
474 // #pragma mark - widget functions
475
476
477 static status_t
hda_widget_get_pm_support(hda_audio_group * audioGroup,hda_widget * widget)478 hda_widget_get_pm_support(hda_audio_group* audioGroup, hda_widget* widget)
479 {
480 return hda_get_pm_support(audioGroup->codec, widget->node_id, &widget->pm);
481 }
482
483
484 static status_t
hda_widget_get_stream_support(hda_audio_group * audioGroup,hda_widget * widget)485 hda_widget_get_stream_support(hda_audio_group* audioGroup, hda_widget* widget)
486 {
487 if (audioGroup->widget.node_id != widget->node_id
488 && (widget->capabilities.audio & AUDIO_CAP_FORMAT_OVERRIDE) == 0) {
489 // adopt capabilities of the audio group
490 widget->d.io.formats = audioGroup->widget.d.io.formats;
491 widget->d.io.rates = audioGroup->widget.d.io.rates;
492 return B_OK;
493 }
494
495 return hda_get_stream_support(audioGroup->codec, widget->node_id,
496 &widget->d.io.formats, &widget->d.io.rates);
497 }
498
499
500 static status_t
hda_widget_get_amplifier_capabilities(hda_audio_group * audioGroup,hda_widget * widget)501 hda_widget_get_amplifier_capabilities(hda_audio_group* audioGroup,
502 hda_widget* widget)
503 {
504 uint32 response;
505 corb_t verb;
506
507 if ((widget->capabilities.audio & AUDIO_CAP_OUTPUT_AMPLIFIER) != 0
508 || audioGroup->widget.node_id == widget->node_id) {
509 if ((widget->capabilities.audio & AUDIO_CAP_AMPLIFIER_OVERRIDE) != 0
510 || audioGroup->widget.node_id == widget->node_id) {
511 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
512 VID_GET_PARAMETER, PID_OUTPUT_AMPLIFIER_CAP);
513 status_t status = hda_send_verbs(audioGroup->codec, &verb,
514 &response, 1);
515 if (status != B_OK)
516 return status;
517
518 widget->capabilities.output_amplifier = response;
519 } else {
520 // adopt capabilities from the audio function group
521 widget->capabilities.output_amplifier
522 = audioGroup->widget.capabilities.output_amplifier;
523 }
524 }
525
526 if ((widget->capabilities.audio & AUDIO_CAP_INPUT_AMPLIFIER) != 0
527 || audioGroup->widget.node_id == widget->node_id) {
528 if ((widget->capabilities.audio & AUDIO_CAP_AMPLIFIER_OVERRIDE
529 || audioGroup->widget.node_id == widget->node_id) != 0) {
530 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
531 VID_GET_PARAMETER, PID_INPUT_AMPLIFIER_CAP);
532 status_t status = hda_send_verbs(audioGroup->codec, &verb,
533 &response, 1);
534 if (status != B_OK)
535 return status;
536
537 widget->capabilities.input_amplifier = response;
538 } else {
539 // adopt capabilities from the audio function group
540 widget->capabilities.input_amplifier
541 = audioGroup->widget.capabilities.input_amplifier;
542 }
543 }
544
545 return B_OK;
546 }
547
548
549 hda_widget*
hda_audio_group_get_widget(hda_audio_group * audioGroup,uint32 nodeID)550 hda_audio_group_get_widget(hda_audio_group* audioGroup, uint32 nodeID)
551 {
552 if (audioGroup->widget_start > nodeID
553 || audioGroup->widget_start + audioGroup->widget_count < nodeID)
554 return NULL;
555
556 return &audioGroup->widgets[nodeID - audioGroup->widget_start];
557 }
558
559
560 static status_t
hda_widget_get_connections(hda_audio_group * audioGroup,hda_widget * widget)561 hda_widget_get_connections(hda_audio_group* audioGroup, hda_widget* widget)
562 {
563 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
564 VID_GET_PARAMETER, PID_CONNECTION_LIST_LENGTH);
565 uint32 response;
566
567 if (hda_send_verbs(audioGroup->codec, &verb, &response, 1) != B_OK)
568 return B_ERROR;
569
570 uint32 listEntries = response & 0x7f;
571 bool longForm = (response & 0xf0) != 0;
572
573 if (listEntries == 0)
574 return B_OK;
575
576 #if 1
577 if (widget->num_inputs > 1) {
578 // Get currently active connection
579 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
580 VID_GET_CONNECTION_SELECT, 0);
581 if (hda_send_verbs(audioGroup->codec, &verb, &response, 1) == B_OK)
582 widget->active_input = response & 0xff;
583 }
584 #endif
585
586 uint32 valuesPerEntry = longForm ? 2 : 4;
587 uint32 shift = 32 / valuesPerEntry;
588 uint32 rangeMask = (1 << (shift - 1));
589 int32 previousInput = -1;
590 uint32 numInputs = 0;
591
592 for (uint32 i = 0; i < listEntries; i++) {
593 if ((i % valuesPerEntry) == 0) {
594 // We get 2 or 4 answers per call depending on if we're
595 // in short or long list mode
596 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
597 VID_GET_CONNECTION_LIST_ENTRY, i);
598 if (hda_send_verbs(audioGroup->codec, &verb, &response, 1)
599 != B_OK) {
600 ERROR("Error parsing inputs for widget %" B_PRIu32 "!\n",
601 widget->node_id);
602 break;
603 }
604 }
605
606 int32 input = (response >> (shift * (i % valuesPerEntry)))
607 & ((1 << shift) - 1);
608
609 if (input & rangeMask) {
610 // found range
611 input &= ~rangeMask;
612
613 if (input < previousInput || previousInput == -1) {
614 ERROR("invalid range from %" B_PRId32 " to %" B_PRId32 "\n",
615 previousInput, input);
616 continue;
617 }
618
619 for (int32 rangeInput = previousInput + 1; rangeInput <= input
620 && numInputs < MAX_INPUTS; rangeInput++) {
621 widget->inputs[numInputs++] = rangeInput;
622 }
623
624 previousInput = -1;
625 } else if (numInputs < MAX_INPUTS) {
626 // standard value
627 widget->inputs[numInputs++] = input;
628 previousInput = input;
629 }
630 }
631
632 widget->num_inputs = numInputs;
633
634 if (widget->num_inputs == 1)
635 widget->active_input = 0;
636
637 return B_OK;
638 }
639
640
641 static status_t
hda_widget_get_associations(hda_audio_group * audioGroup)642 hda_widget_get_associations(hda_audio_group* audioGroup)
643 {
644 uint32 index = 0;
645 for (uint32 i = 0; i < MAX_ASSOCIATIONS; i++) {
646 for (uint32 j = 0; j < audioGroup->widget_count; j++) {
647 if (index >= MAX_ASSOCIATIONS) {
648 TRACE("too many associations, bailing!\n");
649 return B_ERROR;
650 }
651 hda_widget& widget = audioGroup->widgets[j];
652
653 if (widget.type != WT_PIN_COMPLEX)
654 continue;
655 if (CONF_DEFAULT_ASSOCIATION(widget.d.pin.config) != i)
656 continue;
657 if (audioGroup->associations[index].pin_count == 0) {
658 audioGroup->associations[index].index = index;
659 audioGroup->associations[index].enabled = true;
660 }
661 uint32 sequence = CONF_DEFAULT_SEQUENCE(widget.d.pin.config);
662 if (audioGroup->associations[index].pins[sequence] != 0) {
663 audioGroup->associations[index].enabled = false;
664 }
665 audioGroup->associations[index].pins[sequence] = widget.node_id;
666 audioGroup->associations[index].pin_count++;
667 if (i == 15)
668 index++;
669 }
670 if (i != 15 && audioGroup->associations[index].pin_count != 0)
671 index++;
672 }
673 audioGroup->association_count = index;
674
675 return B_OK;
676 }
677
678
679 static uint32
hda_widget_prepare_pin_ctrl(hda_audio_group * audioGroup,hda_widget * widget,bool isOutput)680 hda_widget_prepare_pin_ctrl(hda_audio_group* audioGroup, hda_widget* widget,
681 bool isOutput)
682 {
683 uint32 ctrl = 0;
684 if (isOutput)
685 ctrl = PIN_ENABLE_HEAD_PHONE | PIN_ENABLE_OUTPUT;
686 else
687 ctrl = PIN_ENABLE_INPUT;
688
689 if (PIN_CAP_IS_VREF_CTRL_50_CAP(widget->d.pin.capabilities)
690 && (audioGroup->codec->quirks & (isOutput ? HDA_QUIRK_OVREF50
691 : HDA_QUIRK_IVREF50))) {
692 ctrl |= PIN_ENABLE_VREF_50;
693 TRACE("%s vref 50 enabled\n", isOutput ? "output" : "input");
694 }
695 if (PIN_CAP_IS_VREF_CTRL_80_CAP(widget->d.pin.capabilities)
696 && (audioGroup->codec->quirks & (isOutput ? HDA_QUIRK_OVREF80
697 : HDA_QUIRK_IVREF80))) {
698 ctrl |= PIN_ENABLE_VREF_80;
699 TRACE("%s vref 80 enabled\n", isOutput ? "output" : "input");
700 }
701 if (PIN_CAP_IS_VREF_CTRL_100_CAP(widget->d.pin.capabilities)
702 && (audioGroup->codec->quirks & (isOutput ? HDA_QUIRK_OVREF100
703 : HDA_QUIRK_IVREF100))) {
704 ctrl |= PIN_ENABLE_VREF_100;
705 TRACE("%s vref 100 enabled\n", isOutput ? "output" : "input");
706 }
707
708 return ctrl;
709 }
710
711
712 // #pragma mark - audio group functions
713
714
715 static status_t
hda_codec_parse_audio_group(hda_audio_group * audioGroup)716 hda_codec_parse_audio_group(hda_audio_group* audioGroup)
717 {
718 corb_t verbs[3];
719 uint32 resp[3];
720
721 hda_codec* codec = audioGroup->codec;
722 uint32 codec_id = (codec->vendor_id << 16) | codec->product_id;
723
724 // Power up the audio function
725 verbs[0] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id,
726 VID_SET_POWER_STATE, 0);
727 hda_send_verbs(audioGroup->codec, verbs, NULL, 1);
728
729 hda_widget_get_stream_support(audioGroup, &audioGroup->widget);
730 hda_widget_get_pm_support(audioGroup, &audioGroup->widget);
731 hda_widget_get_amplifier_capabilities(audioGroup, &audioGroup->widget);
732
733 verbs[0] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id,
734 VID_GET_PARAMETER, PID_AUDIO_GROUP_CAP);
735 verbs[1] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id,
736 VID_GET_PARAMETER, PID_GPIO_COUNT);
737 verbs[2] = MAKE_VERB(audioGroup->codec->addr, audioGroup->widget.node_id,
738 VID_GET_PARAMETER, PID_SUB_NODE_COUNT);
739
740 if (hda_send_verbs(audioGroup->codec, verbs, resp, 3) != B_OK)
741 return B_ERROR;
742
743 TRACE("Audio Group: Output delay: %" B_PRIu32 " "
744 "samples, Input delay: %" B_PRIu32 " "
745 "samples, Beep Generator: %s\n", AUDIO_GROUP_CAP_OUTPUT_DELAY(resp[0]),
746 AUDIO_GROUP_CAP_INPUT_DELAY(resp[0]),
747 AUDIO_GROUP_CAP_BEEPGEN(resp[0]) ? "yes" : "no");
748
749 TRACE(" #GPIO: %" B_PRIu32 ", #GPO: %" B_PRIu32 ", #GPI: %" B_PRIu32 ", "
750 "unsol: %s, wake: %s\n",
751 GPIO_COUNT_NUM_GPIO(resp[1]), GPIO_COUNT_NUM_GPO(resp[1]),
752 GPIO_COUNT_NUM_GPI(resp[1]), GPIO_COUNT_GPIUNSOL(resp[1]) ? "yes" : "no",
753 GPIO_COUNT_GPIWAKE(resp[1]) ? "yes" : "no");
754 dump_widget_stream_support(audioGroup->widget);
755
756 audioGroup->gpio = resp[1];
757 audioGroup->widget_start = SUB_NODE_COUNT_START(resp[2]);
758 audioGroup->widget_count = SUB_NODE_COUNT_TOTAL(resp[2]);
759
760 TRACE(" widget start %" B_PRIu32 ", count %" B_PRIu32 "\n",
761 audioGroup->widget_start, audioGroup->widget_count);
762
763 audioGroup->widgets = (hda_widget*)calloc(audioGroup->widget_count,
764 sizeof(*audioGroup->widgets));
765 if (audioGroup->widgets == NULL) {
766 ERROR("ERROR: Not enough memory!\n");
767 return B_NO_MEMORY;
768 }
769
770 // Iterate over all Widgets and collect info
771 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
772 hda_widget& widget = audioGroup->widgets[i];
773 uint32 nodeID = audioGroup->widget_start + i;
774 uint32 capabilities;
775
776 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, VID_GET_PARAMETER,
777 PID_AUDIO_WIDGET_CAP);
778 if (hda_send_verbs(audioGroup->codec, verbs, &capabilities, 1) != B_OK)
779 return B_ERROR;
780
781 widget.type = (hda_widget_type)((capabilities & AUDIO_CAP_TYPE_MASK)
782 >> AUDIO_CAP_TYPE_SHIFT);
783
784 // Check specific node ids declared as inputs as beepers
785 switch (codec_id) {
786 case 0x11d41882:
787 case 0x11d41883:
788 case 0x11d41884:
789 case 0x11d4194a:
790 case 0x11d4194b:
791 case 0x11d41987:
792 case 0x11d41988:
793 case 0x11d4198b:
794 case 0x11d4989b:
795 if (nodeID == 26)
796 widget.type = WT_BEEP_GENERATOR;
797 break;
798 case 0x10ec0260:
799 if (nodeID == 23)
800 widget.type = WT_BEEP_GENERATOR;
801 break;
802 case 0x10ec0262:
803 case 0x10ec0268:
804 case 0x10ec0880:
805 case 0x10ec0882:
806 case 0x10ec0883:
807 case 0x10ec0885:
808 case 0x10ec0888:
809 case 0x10ec0889:
810 if (nodeID == 29)
811 widget.type = WT_BEEP_GENERATOR;
812 break;
813 }
814 widget.active_input = -1;
815 widget.capabilities.audio = capabilities;
816 widget.node_id = nodeID;
817
818 if ((capabilities & AUDIO_CAP_POWER_CONTROL) != 0) {
819 // We support power; switch us on!
820 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
821 VID_SET_POWER_STATE, 0);
822 hda_send_verbs(audioGroup->codec, verbs, NULL, 1);
823
824 snooze(1000);
825 }
826 if ((capabilities & (AUDIO_CAP_INPUT_AMPLIFIER
827 | AUDIO_CAP_OUTPUT_AMPLIFIER)) != 0) {
828 hda_widget_get_amplifier_capabilities(audioGroup, &widget);
829 }
830
831 TRACE("%" B_PRIu32 ": %s\n", nodeID, get_widget_type_name(widget.type));
832
833 switch (widget.type) {
834 case WT_AUDIO_OUTPUT:
835 case WT_AUDIO_INPUT:
836 hda_widget_get_stream_support(audioGroup, &widget);
837 dump_widget_stream_support(widget);
838 break;
839
840 case WT_PIN_COMPLEX:
841 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
842 VID_GET_PARAMETER, PID_PIN_CAP);
843 if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) {
844 widget.d.pin.capabilities = resp[0];
845
846 TRACE("\t%s%s\n", PIN_CAP_IS_INPUT(resp[0]) ? "[Input] " : "",
847 PIN_CAP_IS_OUTPUT(resp[0]) ? "[Output]" : "");
848 } else {
849 ERROR("%s: Error getting Pin Complex IO\n", __func__);
850 }
851
852 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
853 VID_GET_CONFIGURATION_DEFAULT, 0);
854 if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) {
855 widget.d.pin.config = resp[0];
856 const char* location =
857 get_widget_location(CONF_DEFAULT_LOCATION(resp[0]));
858 TRACE("\t%s, %s%s%s, %s, %s, Association:%" B_PRIu32 "\n",
859 kPortConnector[CONF_DEFAULT_CONNECTIVITY(resp[0])],
860 location ? location : "",
861 location ? " " : "",
862 kDefaultDevice[CONF_DEFAULT_DEVICE(resp[0])],
863 kConnectionType[CONF_DEFAULT_CONNTYPE(resp[0])],
864 kJackColor[CONF_DEFAULT_COLOR(resp[0])],
865 CONF_DEFAULT_ASSOCIATION(resp[0]));
866 }
867 break;
868
869 case WT_VOLUME_KNOB:
870 verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
871 VID_SET_VOLUME_KNOB_CONTROL, 0x0);
872 hda_send_verbs(audioGroup->codec, verbs, NULL, 1);
873 break;
874 default:
875 break;
876 }
877
878 hda_widget_get_pm_support(audioGroup, &widget);
879 hda_widget_get_connections(audioGroup, &widget);
880
881 dump_widget_pm_support(widget);
882 dump_widget_audio_capabilities(capabilities);
883 dump_widget_amplifier_capabilities(widget, true);
884 dump_widget_amplifier_capabilities(widget, false);
885 dump_widget_inputs(widget);
886 }
887
888 hda_widget_get_associations(audioGroup);
889
890 // init the codecs
891 switch (codec_id) {
892 case 0x10ec0888: {
893 hda_verb_write(codec, 0x20, VID_SET_COEFFICIENT_INDEX, 0x0);
894 uint32 tmp;
895 hda_verb_read(codec, 0x20, VID_GET_PROCESSING_COEFFICIENT, &tmp);
896 hda_verb_write(codec, 0x20, VID_SET_COEFFICIENT_INDEX, 0x7);
897 hda_verb_write(codec, 0x20, VID_SET_PROCESSING_COEFFICIENT,
898 (tmp & 0xf0) == 0x20 ? 0x830 : 0x3030);
899 break;
900 }
901 }
902
903 return B_OK;
904 }
905
906
907 /*! Find output path for widget */
908 static bool
hda_widget_find_output_path(hda_audio_group * audioGroup,hda_widget * widget,uint32 depth,bool & alreadyUsed)909 hda_widget_find_output_path(hda_audio_group* audioGroup, hda_widget* widget,
910 uint32 depth, bool &alreadyUsed)
911 {
912 alreadyUsed = false;
913
914 if (widget == NULL || depth > 16)
915 return false;
916
917 switch (widget->type) {
918 case WT_AUDIO_OUTPUT:
919 widget->flags |= WIDGET_FLAG_OUTPUT_PATH;
920 TRACE(" %*soutput: added output widget %" B_PRIu32 "\n",
921 (int)depth * 2, "", widget->node_id);
922 return true;
923
924 case WT_AUDIO_MIXER:
925 case WT_AUDIO_SELECTOR:
926 {
927 // already used
928 if ((widget->flags & WIDGET_FLAG_OUTPUT_PATH) != 0) {
929 alreadyUsed = true;
930 return false;
931 }
932
933 // search for output in this path
934 bool found = false;
935 for (uint32 i = 0; i < widget->num_inputs; i++) {
936 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup,
937 widget->inputs[i]);
938
939 if (hda_widget_find_output_path(audioGroup, inputWidget,
940 depth + 1, alreadyUsed)) {
941 if (widget->active_input == -1)
942 widget->active_input = i;
943
944 widget->flags |= WIDGET_FLAG_OUTPUT_PATH;
945 TRACE(" %*soutput: added mixer/selector widget %"
946 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id);
947 found = true;
948 }
949 }
950 if (!found) TRACE(" %*soutput: not added mixer/selector widget %"
951 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id);
952 return found;
953 }
954
955 default:
956 return false;
957 }
958 }
959
960
961 /*! Find input path for widget */
962 static bool
hda_widget_find_input_path(hda_audio_group * audioGroup,hda_widget * widget,uint32 depth)963 hda_widget_find_input_path(hda_audio_group* audioGroup, hda_widget* widget,
964 uint32 depth)
965 {
966 if (widget == NULL || depth > 16)
967 return false;
968
969 switch (widget->type) {
970 case WT_PIN_COMPLEX:
971 // already used
972 if ((widget->flags
973 & (WIDGET_FLAG_INPUT_PATH | WIDGET_FLAG_OUTPUT_PATH)) != 0)
974 return false;
975
976 if (PIN_CAP_IS_INPUT(widget->d.pin.capabilities)) {
977 switch (CONF_DEFAULT_DEVICE(widget->d.pin.config)) {
978 case PIN_DEV_CD:
979 case PIN_DEV_LINE_IN:
980 case PIN_DEV_MIC_IN:
981 widget->flags |= WIDGET_FLAG_INPUT_PATH;
982 TRACE(" %*sinput: added input widget %" B_PRIu32 "\n",
983 (int)depth * 2, "", widget->node_id);
984 return true;
985 break;
986 }
987 }
988 return false;
989 case WT_AUDIO_INPUT:
990 case WT_AUDIO_MIXER:
991 case WT_AUDIO_SELECTOR:
992 {
993 // already used
994 if ((widget->flags
995 & (WIDGET_FLAG_INPUT_PATH | WIDGET_FLAG_OUTPUT_PATH)) != 0)
996 return false;
997
998 // search for pin complex in this path
999 bool found = false;
1000 for (uint32 i = 0; i < widget->num_inputs; i++) {
1001 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup,
1002 widget->inputs[i]);
1003
1004 if (hda_widget_find_input_path(audioGroup, inputWidget,
1005 depth + 1)) {
1006 if (widget->active_input == -1)
1007 widget->active_input = i;
1008
1009 widget->flags |= WIDGET_FLAG_INPUT_PATH;
1010 TRACE(" %*sinput: added mixer/selector widget %"
1011 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id);
1012 found = true;
1013 }
1014 }
1015 if (!found) TRACE(" %*sinput: not added mixer/selector widget %"
1016 B_PRIu32 "\n", (int)depth * 2, "", widget->node_id);
1017 return found;
1018 }
1019
1020 default:
1021 return false;
1022 }
1023 }
1024
1025 static bool
hda_audio_group_build_output_tree(hda_audio_group * audioGroup,bool useMixer)1026 hda_audio_group_build_output_tree(hda_audio_group* audioGroup, bool useMixer)
1027 {
1028 bool found = false;
1029
1030 TRACE("build output tree: %suse mixer\n", useMixer ? "" : "don't ");
1031 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
1032 hda_widget& widget = audioGroup->widgets[i];
1033
1034 if (widget.type != WT_PIN_COMPLEX
1035 || !PIN_CAP_IS_OUTPUT(widget.d.pin.capabilities))
1036 continue;
1037
1038 int device = CONF_DEFAULT_DEVICE(widget.d.pin.config);
1039 if (device != PIN_DEV_HEAD_PHONE_OUT
1040 && device != PIN_DEV_DIGITAL_OTHER_OUT
1041 && device != PIN_DEV_SPEAKER
1042 && device != PIN_DEV_LINE_OUT)
1043 continue;
1044
1045 TRACE(" look at pin widget %" B_PRIu32 " (%" B_PRIu32 " inputs)\n",
1046 widget.node_id, widget.num_inputs);
1047 for (uint32 j = 0; j < widget.num_inputs; j++) {
1048 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup,
1049 widget.inputs[j]);
1050 TRACE(" try widget %" B_PRIu32 ": %p\n",
1051 widget.inputs[j], inputWidget);
1052 if (inputWidget == NULL)
1053 continue;
1054
1055 if (useMixer && inputWidget->type != WT_AUDIO_MIXER
1056 && inputWidget->type != WT_AUDIO_SELECTOR)
1057 continue;
1058 TRACE(" widget %" B_PRIu32 " is candidate\n", inputWidget->node_id);
1059
1060 bool alreadyUsed = false;
1061 if (hda_widget_find_output_path(audioGroup, inputWidget, 0,
1062 alreadyUsed)
1063 || (device == PIN_DEV_HEAD_PHONE_OUT && alreadyUsed)) {
1064 // find the output path to an audio output widget
1065 // or for headphones, an already used widget
1066 TRACE(" add pin widget %" B_PRIu32 "\n", widget.node_id);
1067 if (widget.active_input == -1)
1068 widget.active_input = j;
1069 widget.flags |= WIDGET_FLAG_OUTPUT_PATH;
1070 found = true;
1071 break;
1072 }
1073 }
1074 }
1075
1076 return found;
1077 }
1078
1079
1080 static bool
hda_audio_group_build_input_tree(hda_audio_group * audioGroup)1081 hda_audio_group_build_input_tree(hda_audio_group* audioGroup)
1082 {
1083 bool found = false;
1084
1085 TRACE("build input tree\n");
1086 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
1087 hda_widget& widget = audioGroup->widgets[i];
1088
1089 if (widget.type != WT_AUDIO_INPUT)
1090 continue;
1091
1092 TRACE(" look at input widget %" B_PRIu32 " (%" B_PRIu32 " inputs)\n",
1093 widget.node_id, widget.num_inputs);
1094 for (uint32 j = 0; j < widget.num_inputs; j++) {
1095 hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup,
1096 widget.inputs[j]);
1097 TRACE(" try widget %" B_PRIu32 ": %p\n",
1098 widget.inputs[j], inputWidget);
1099 if (inputWidget == NULL)
1100 continue;
1101
1102 TRACE(" widget %" B_PRIu32 " is candidate\n",
1103 inputWidget->node_id);
1104
1105 if (hda_widget_find_input_path(audioGroup, inputWidget, 0)) {
1106 TRACE(" add pin widget %" B_PRIu32 "\n", widget.node_id);
1107 if (widget.active_input == -1)
1108 widget.active_input = j;
1109 widget.flags |= WIDGET_FLAG_INPUT_PATH;
1110 found = true;
1111 break;
1112 }
1113 }
1114 }
1115
1116 return found;
1117 }
1118
1119
1120 static status_t
hda_audio_group_build_tree(hda_audio_group * audioGroup)1121 hda_audio_group_build_tree(hda_audio_group* audioGroup)
1122 {
1123 if (!hda_audio_group_build_output_tree(audioGroup, true)) {
1124 // didn't find a mixer path, try again without
1125 TRACE("try without mixer!\n");
1126 if (!hda_audio_group_build_output_tree(audioGroup, false))
1127 return ENODEV;
1128 }
1129
1130 if (!hda_audio_group_build_input_tree(audioGroup)) {
1131 ERROR("build input tree failed\n");
1132 }
1133
1134 TRACE("build tree!\n");
1135
1136 // select active connections
1137
1138 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
1139 hda_widget& widget = audioGroup->widgets[i];
1140
1141 if (widget.active_input == -1)
1142 widget.active_input = 0;
1143 if (widget.num_inputs < 2)
1144 continue;
1145
1146 if (widget.type != WT_AUDIO_INPUT
1147 && widget.type != WT_AUDIO_SELECTOR
1148 && widget.type != WT_PIN_COMPLEX)
1149 continue;
1150
1151 corb_t verb = MAKE_VERB(audioGroup->codec->addr,
1152 widget.node_id, VID_SET_CONNECTION_SELECT, widget.active_input);
1153 if (hda_send_verbs(audioGroup->codec, &verb, NULL, 1) != B_OK)
1154 ERROR("Setting output selector %" B_PRIu32
1155 " failed on widget %" B_PRIu32 "!\n",
1156 widget.active_input, widget.node_id);
1157 }
1158
1159 // GPIO
1160 uint32 gpio = 0;
1161 for (uint32 i = 0; i < GPIO_COUNT_NUM_GPIO(audioGroup->gpio)
1162 && i < HDA_QUIRK_GPIO_COUNT; i++) {
1163 if (audioGroup->codec->quirks & (1 << i)) {
1164 gpio |= (1 << i);
1165 }
1166 }
1167
1168 if (gpio != 0) {
1169 corb_t verb[] = {
1170 MAKE_VERB(audioGroup->codec->addr,
1171 audioGroup->widget.node_id, VID_SET_GPIO_DATA, gpio),
1172 MAKE_VERB(audioGroup->codec->addr,
1173 audioGroup->widget.node_id, VID_SET_GPIO_EN, gpio),
1174 MAKE_VERB(audioGroup->codec->addr,
1175 audioGroup->widget.node_id, VID_SET_GPIO_DIR, gpio)
1176 };
1177 TRACE("Setting gpio 0x%" B_PRIx32 "\n", gpio);
1178 if (hda_send_verbs(audioGroup->codec, verb, NULL, 3) != B_OK)
1179 ERROR("Setting gpio failed!\n");
1180 }
1181
1182 dump_audiogroup_widgets(audioGroup);
1183
1184 return B_OK;
1185 }
1186
1187
1188 static void
hda_audio_group_switch_init(hda_audio_group * audioGroup)1189 hda_audio_group_switch_init(hda_audio_group* audioGroup)
1190 {
1191 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
1192 hda_widget& widget = audioGroup->widgets[i];
1193 if (widget.type != WT_PIN_COMPLEX)
1194 continue;
1195
1196 if ((widget.capabilities.audio & AUDIO_CAP_UNSOLICITED_RESPONSES) != 0
1197 && (widget.d.pin.capabilities & PIN_CAP_PRES_DETECT) != 0
1198 && (CONF_DEFAULT_MISC(widget.d.pin.config) & 1) == 0) {
1199 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id,
1200 VID_SET_UNSOLRESP, UNSOLRESP_ENABLE);
1201 hda_send_verbs(audioGroup->codec, &verb, NULL, 1);
1202 TRACE("Enabled unsolicited responses on widget %" B_PRIu32 "\n",
1203 widget.node_id);
1204 }
1205 }
1206 }
1207
1208
1209 static void
hda_audio_group_check_sense(hda_audio_group * audioGroup,bool disable)1210 hda_audio_group_check_sense(hda_audio_group* audioGroup, bool disable)
1211 {
1212 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
1213 hda_widget& widget = audioGroup->widgets[i];
1214
1215 if (widget.type != WT_PIN_COMPLEX
1216 || !PIN_CAP_IS_OUTPUT(widget.d.pin.capabilities)
1217 || CONF_DEFAULT_DEVICE(widget.d.pin.config)
1218 != PIN_DEV_HEAD_PHONE_OUT)
1219 continue;
1220
1221 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id,
1222 VID_GET_PINSENSE, 0);
1223 uint32 response;
1224 hda_send_verbs(audioGroup->codec, &verb, &response, 1);
1225 disable = response & PIN_SENSE_PRESENCE_DETECT;
1226 TRACE("sensed pin widget %" B_PRIu32 ", %d\n", widget.node_id, disable);
1227
1228 uint32 ctrl = hda_widget_prepare_pin_ctrl(audioGroup, &widget,
1229 true);
1230 verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id,
1231 VID_SET_PIN_WIDGET_CONTROL, disable ? ctrl : 0);
1232 hda_send_verbs(audioGroup->codec, &verb, NULL, 1);
1233 break;
1234 }
1235
1236 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
1237 hda_widget& widget = audioGroup->widgets[i];
1238
1239 if (widget.type != WT_PIN_COMPLEX
1240 || !PIN_CAP_IS_OUTPUT(widget.d.pin.capabilities))
1241 continue;
1242
1243 int device = CONF_DEFAULT_DEVICE(widget.d.pin.config);
1244 if (device != PIN_DEV_AUX
1245 && device != PIN_DEV_SPEAKER
1246 && device != PIN_DEV_LINE_OUT)
1247 continue;
1248
1249 uint32 ctrl = hda_widget_prepare_pin_ctrl(audioGroup, &widget,
1250 true);
1251 corb_t verb = MAKE_VERB(audioGroup->codec->addr, widget.node_id,
1252 VID_SET_PIN_WIDGET_CONTROL, disable ? 0 : ctrl);
1253 hda_send_verbs(audioGroup->codec, &verb, NULL, 1);
1254 }
1255 }
1256
1257
1258 static status_t
hda_codec_switch_handler(hda_codec * codec)1259 hda_codec_switch_handler(hda_codec* codec)
1260 {
1261 while (acquire_sem(codec->unsol_response_sem) == B_OK) {
1262 uint32 response = codec->unsol_responses[codec->unsol_response_read++];
1263 codec->unsol_response_read %= MAX_CODEC_UNSOL_RESPONSES;
1264
1265 bool disable = response & 1;
1266 hda_audio_group* audioGroup = codec->audio_groups[0];
1267 hda_audio_group_check_sense(audioGroup, disable);
1268 }
1269 return B_OK;
1270 }
1271
1272
1273 static void
hda_codec_delete_audio_group(hda_audio_group * audioGroup)1274 hda_codec_delete_audio_group(hda_audio_group* audioGroup)
1275 {
1276 if (audioGroup == NULL)
1277 return;
1278
1279 if (audioGroup->playback_stream != NULL)
1280 hda_stream_delete(audioGroup->playback_stream);
1281
1282 if (audioGroup->record_stream != NULL)
1283 hda_stream_delete(audioGroup->record_stream);
1284 free(audioGroup->multi);
1285 free(audioGroup->widgets);
1286 free(audioGroup);
1287 }
1288
1289
1290 static status_t
hda_codec_new_audio_group(hda_codec * codec,uint32 audioGroupNodeID)1291 hda_codec_new_audio_group(hda_codec* codec, uint32 audioGroupNodeID)
1292 {
1293 hda_audio_group* audioGroup = (hda_audio_group*)calloc(1,
1294 sizeof(hda_audio_group));
1295 if (audioGroup == NULL)
1296 return B_NO_MEMORY;
1297
1298 // Setup minimal info needed by hda_codec_parse_afg
1299 audioGroup->widget.node_id = audioGroupNodeID;
1300 audioGroup->codec = codec;
1301 audioGroup->multi = (hda_multi*)calloc(1,
1302 sizeof(hda_multi));
1303 if (audioGroup->multi == NULL) {
1304 free(audioGroup);
1305 return B_NO_MEMORY;
1306 }
1307 audioGroup->multi->group = audioGroup;
1308
1309 // Parse all widgets in Audio Function Group
1310 status_t status = hda_codec_parse_audio_group(audioGroup);
1311 if (status != B_OK)
1312 goto err;
1313
1314 // Setup for worst-case scenario; we cannot find any output Pin Widgets
1315 status = ENODEV;
1316
1317 if (hda_audio_group_build_tree(audioGroup) != B_OK)
1318 goto err;
1319 hda_audio_group_switch_init(audioGroup);
1320
1321 audioGroup->playback_stream = hda_stream_new(audioGroup, STREAM_PLAYBACK);
1322 audioGroup->record_stream = hda_stream_new(audioGroup, STREAM_RECORD);
1323 TRACE("streams playback %p, record %p\n", audioGroup->playback_stream,
1324 audioGroup->record_stream);
1325
1326 if (audioGroup->playback_stream != NULL
1327 || audioGroup->record_stream != NULL) {
1328 codec->audio_groups[codec->num_audio_groups++] = audioGroup;
1329 hda_audio_group_check_sense(audioGroup, false);
1330 return B_OK;
1331 }
1332
1333 err:
1334 free(audioGroup->widgets);
1335 free(audioGroup);
1336 return status;
1337 }
1338
1339
1340 // #pragma mark -
1341
1342
1343 status_t
hda_audio_group_get_widgets(hda_audio_group * audioGroup,hda_stream * stream)1344 hda_audio_group_get_widgets(hda_audio_group* audioGroup, hda_stream* stream)
1345 {
1346 hda_widget_type type;
1347 uint32 flags;
1348
1349 if (stream->type == STREAM_PLAYBACK) {
1350 type = WT_AUDIO_OUTPUT;
1351 flags = WIDGET_FLAG_OUTPUT_PATH;
1352 } else {
1353 // record
1354 type = WT_AUDIO_INPUT;
1355 flags = WIDGET_FLAG_INPUT_PATH;
1356 }
1357
1358 uint32 count = 0;
1359
1360 for (uint32 i = 0; i < audioGroup->widget_count && count < MAX_IO_WIDGETS;
1361 i++) {
1362 hda_widget& widget = audioGroup->widgets[i];
1363
1364 if ((widget.flags & flags) != 0) {
1365 if (widget.type == WT_PIN_COMPLEX) {
1366 stream->pin_widget = widget.node_id;
1367
1368 uint32 ctrl = hda_widget_prepare_pin_ctrl(audioGroup, &widget,
1369 flags == WIDGET_FLAG_OUTPUT_PATH);
1370
1371 TRACE("ENABLE pin widget %" B_PRIu32 "\n", widget.node_id);
1372 // FIXME: Force Pin Widget to unmute; enable hp/output
1373 corb_t verb = MAKE_VERB(audioGroup->codec->addr,
1374 widget.node_id,
1375 VID_SET_PIN_WIDGET_CONTROL, ctrl);
1376 hda_send_verbs(audioGroup->codec, &verb, NULL, 1);
1377
1378 if (PIN_CAP_IS_EAPD_CAP(widget.d.pin.capabilities)) {
1379 uint32 result;
1380 verb = MAKE_VERB(audioGroup->codec->addr,
1381 widget.node_id, VID_GET_EAPDBTL_EN, 0);
1382 if (hda_send_verbs(audioGroup->codec, &verb,
1383 &result, 1) == B_OK) {
1384 result &= 0xff;
1385 verb = MAKE_VERB(audioGroup->codec->addr,
1386 widget.node_id, VID_SET_EAPDBTL_EN,
1387 result | EAPDBTL_ENABLE_EAPD);
1388 hda_send_verbs(audioGroup->codec,
1389 &verb, NULL, 1);
1390 TRACE("ENABLE EAPD pin widget %" B_PRIu32 "\n",
1391 widget.node_id);
1392 }
1393 }
1394 }
1395
1396 if (widget.capabilities.output_amplifier != 0) {
1397 TRACE("UNMUTE/SET OUTPUT GAIN widget %" B_PRIu32 " "
1398 "(offset %" B_PRIu32 ")\n", widget.node_id,
1399 AMP_CAP_OFFSET(widget.capabilities.output_amplifier));
1400 corb_t verb = MAKE_VERB(audioGroup->codec->addr,
1401 widget.node_id,
1402 VID_SET_AMPLIFIER_GAIN_MUTE,
1403 AMP_SET_OUTPUT | AMP_SET_LEFT_CHANNEL
1404 | AMP_SET_RIGHT_CHANNEL
1405 | AMP_CAP_OFFSET(widget.capabilities.output_amplifier));
1406 hda_send_verbs(audioGroup->codec, &verb, NULL, 1);
1407 }
1408 if (widget.capabilities.input_amplifier != 0) {
1409 TRACE("UNMUTE/SET INPUT GAIN widget %" B_PRIu32 " "
1410 "(offset %" B_PRIu32 ")\n", widget.node_id,
1411 AMP_CAP_OFFSET(widget.capabilities.input_amplifier));
1412 for (uint32 i = 0; i < widget.num_inputs; i++) {
1413 corb_t verb = MAKE_VERB(audioGroup->codec->addr,
1414 widget.node_id,
1415 VID_SET_AMPLIFIER_GAIN_MUTE,
1416 AMP_SET_INPUT | AMP_SET_LEFT_CHANNEL
1417 | AMP_SET_RIGHT_CHANNEL
1418 | AMP_SET_INPUT_INDEX(i)
1419 | ((widget.active_input == (int32)i) ? 0 : AMP_MUTE)
1420 | AMP_CAP_OFFSET(widget.capabilities.input_amplifier));
1421 hda_send_verbs(audioGroup->codec, &verb, NULL, 1);
1422 }
1423 }
1424 }
1425
1426 if (widget.type != type || (widget.flags & flags) == 0
1427 || (widget.capabilities.audio
1428 & (AUDIO_CAP_STEREO | AUDIO_CAP_DIGITAL)) != AUDIO_CAP_STEREO
1429 || widget.d.io.formats == 0)
1430 continue;
1431
1432 if (count == 0) {
1433 stream->sample_format = widget.d.io.formats;
1434 stream->sample_rate = widget.d.io.rates;
1435 } else {
1436 stream->sample_format &= widget.d.io.formats;
1437 stream->sample_rate &= widget.d.io.rates;
1438 }
1439
1440 stream->io_widgets[count++] = widget.node_id;
1441 }
1442
1443 if (count == 0)
1444 return B_ENTRY_NOT_FOUND;
1445
1446 stream->num_io_widgets = count;
1447 return B_OK;
1448 }
1449
1450
1451 void
hda_codec_delete(hda_codec * codec)1452 hda_codec_delete(hda_codec* codec)
1453 {
1454 if (codec == NULL)
1455 return;
1456
1457 delete_sem(codec->response_sem);
1458 delete_sem(codec->unsol_response_sem);
1459
1460 int32 result;
1461 wait_for_thread(codec->unsol_response_thread, &result);
1462
1463 for (uint32 i = 0; i < codec->num_audio_groups; i++) {
1464 hda_codec_delete_audio_group(codec->audio_groups[i]);
1465 codec->audio_groups[i] = NULL;
1466 }
1467
1468 free(codec);
1469 }
1470
1471
1472 hda_codec*
hda_codec_new(hda_controller * controller,uint32 codecAddress)1473 hda_codec_new(hda_controller* controller, uint32 codecAddress)
1474 {
1475 if (codecAddress > HDA_MAX_CODECS)
1476 return NULL;
1477
1478 hda_codec* codec = (hda_codec*)calloc(1, sizeof(hda_codec));
1479 if (codec == NULL) {
1480 ERROR("Failed to alloc a codec\n");
1481 return NULL;
1482 }
1483
1484 status_t status;
1485
1486 codec->controller = controller;
1487 codec->addr = codecAddress;
1488 codec->response_sem = create_sem(0, "hda_codec_response_sem");
1489 if (codec->response_sem < B_OK) {
1490 ERROR("Failed to create semaphore\n");
1491 goto err;
1492 }
1493 controller->codecs[codecAddress] = codec;
1494
1495 codec->unsol_response_sem = create_sem(0, "hda_codec_unsol_response_sem");
1496 if (codec->unsol_response_sem < B_OK) {
1497 ERROR("Failed to create semaphore\n");
1498 goto err;
1499 }
1500 codec->unsol_response_read = 0;
1501 codec->unsol_response_write = 0;
1502
1503 struct {
1504 uint16 device;
1505 uint16 vendor;
1506 uint32 subsystem;
1507 uint8 stepping;
1508 uint8 revision;
1509 uint8 minor : 4;
1510 uint8 major : 4;
1511 uint8 _reserved0;
1512 uint8 count;
1513 uint8 _reserved1;
1514 uint8 start;
1515 uint8 _reserved2;
1516 } response;
1517
1518 corb_t verbs[4];
1519 verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
1520 verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_SUBSYSTEM_ID);
1521 verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
1522 verbs[3] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER,
1523 PID_SUB_NODE_COUNT);
1524
1525 status = hda_send_verbs(codec, verbs, (uint32*)&response, 4);
1526 if (status != B_OK) {
1527 ERROR("Failed to get vendor and revision parameters: %s\n",
1528 strerror(status));
1529 goto err;
1530 }
1531
1532 codec->vendor_id = response.vendor;
1533 codec->subsystem_id = response.subsystem;
1534 codec->product_id = response.device;
1535 codec->stepping = response.stepping;
1536 codec->revision = response.revision;
1537 codec->minor = response.minor;
1538 codec->major = response.major;
1539 hda_codec_get_quirks(codec);
1540
1541 for (uint32 nodeID = response.start;
1542 nodeID < response.start + response.count; nodeID++) {
1543 struct {
1544 uint32 groupType;
1545 uint32 subsystem;
1546 } functionResponse;
1547 verbs[0] = MAKE_VERB(codecAddress, nodeID, VID_GET_PARAMETER,
1548 PID_FUNCTION_GROUP_TYPE);
1549 verbs[1] = MAKE_VERB(codecAddress, nodeID, VID_GET_SUBSYSTEMID, 0);
1550
1551 if (hda_send_verbs(codec, verbs, (uint32*)&functionResponse, 2) != B_OK) {
1552 ERROR("Failed to get function group type\n");
1553 goto err;
1554 }
1555
1556 if ((functionResponse.groupType & FUNCTION_GROUP_NODETYPE_MASK)
1557 == FUNCTION_GROUP_NODETYPE_AUDIO) {
1558 // Found an Audio Function Group!
1559 if (response.subsystem == 0 && functionResponse.subsystem != 0) {
1560 // Update our subsystem, and re-check quirks for this codec
1561 codec->subsystem_id = functionResponse.subsystem;
1562 hda_codec_get_quirks(codec);
1563 }
1564
1565 status_t status = hda_codec_new_audio_group(codec, nodeID);
1566 if (status != B_OK) {
1567 ERROR("Failed to setup new audio function group (%s)!\n",
1568 strerror(status));
1569 goto err;
1570 }
1571 }
1572 }
1573
1574 TRACE("Codec %" B_PRIu32 " Vendor: %04" B_PRIx16 " Product: %04" B_PRIx16 " "
1575 "Subsystem: %08" B_PRIx32 ", "
1576 "Revision: %" B_PRIu8 ".%" B_PRIu8 ".%" B_PRIu8 ".%" B_PRIu8 " "
1577 "Quirks: %04" B_PRIx32 "\n",
1578 codecAddress, response.vendor, response.device,
1579 (uint32)codec->subsystem_id,
1580 response.major, response.minor, response.revision, response.stepping,
1581 codec->quirks);
1582
1583 codec->unsol_response_thread = spawn_kernel_thread(
1584 (status_t(*)(void*))hda_codec_switch_handler,
1585 "hda_codec_unsol_thread", B_LOW_PRIORITY, codec);
1586 if (codec->unsol_response_thread < B_OK) {
1587 ERROR("Failed to spawn thread\n");
1588 goto err;
1589 }
1590 resume_thread(codec->unsol_response_thread);
1591
1592 return codec;
1593
1594 err:
1595 controller->codecs[codecAddress] = NULL;
1596 hda_codec_delete(codec);
1597 return NULL;
1598 }
1599