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