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