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