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