xref: /haiku/src/add-ons/kernel/drivers/audio/hda/hda_codec.cpp (revision 9b655000bc9b9bed75a557b2ef2114375bd0bd40)
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