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