xref: /haiku/src/add-ons/kernel/drivers/audio/hda/hda_codec.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
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 	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("\tConnections: %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: %ld dB, # steps: %ld, offset to 0 dB: "
134 		"%ld\n", input ? "In" : "Out",
135 		(capabilities & AMP_CAP_MUTE) != 0 ? "supports mute, " : "",
136 		(((capabilities & AMP_CAP_STEP_SIZE_MASK)
137 			>> AMP_CAP_STEP_SIZE_SHIFT) + 1) / 4,
138 		(capabilities & AMP_CAP_NUM_STEPS_MASK) >> AMP_CAP_NUM_STEPS_SHIFT,
139 		capabilities & AMP_CAP_OFFSET_MASK);
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_audiogroup_widgets(hda_audio_group* audioGroup)
156 {
157 	dprintf("\tAudiogroup:\n");
158 	/* Iterate over all Widgets and collect info */
159 	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
160 		hda_widget& widget = audioGroup->widgets[i];
161 		uint32 nodeID = audioGroup->widget_start + i;
162 
163 		dprintf("%ld: %s\n", nodeID, get_widget_type_name(widget.type));
164 
165 		switch (widget.type) {
166 			case WT_AUDIO_OUTPUT:
167 			case WT_AUDIO_INPUT:
168 				break;
169 
170 			case WT_PIN_COMPLEX:
171 				dprintf("\t%s%s\n", widget.d.pin.input ? "[Input] " : "",
172 					widget.d.pin.output ? "[Output]" : "");
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 
268 //FIXME:	if (resp[0] & (1 << 2))	/* Sort out how to handle AC3 */;
269 
270 	return B_OK;
271 }
272 
273 
274 //	#pragma mark - widget functions
275 
276 
277 static status_t
278 hda_widget_get_pm_support(hda_audio_group* audioGroup, hda_widget* widget)
279 {
280 	return hda_get_pm_support(audioGroup->codec, widget->node_id,
281 		&widget->pm);
282 }
283 
284 
285 static status_t
286 hda_widget_get_stream_support(hda_audio_group* audioGroup, hda_widget* widget)
287 {
288 	if ((widget->capabilities.audio & AUDIO_CAP_FORMAT_OVERRIDE) == 0) {
289 		// adopt capabilities of the audio group
290 		widget->d.io.formats = audioGroup->supported_formats;
291 		widget->d.io.rates = audioGroup->supported_rates;
292 		return B_OK;
293 	}
294 
295 	return hda_get_stream_support(audioGroup->codec, widget->node_id,
296 		&widget->d.io.formats, &widget->d.io.rates);
297 }
298 
299 
300 static status_t
301 hda_widget_get_amplifier_capabilities(hda_audio_group* audioGroup,
302 	hda_widget* widget)
303 {
304 	uint32 response;
305 	corb_t verb;
306 
307 	if ((widget->capabilities.audio & AUDIO_CAP_OUTPUT_AMPLIFIER) != 0) {
308 		if ((widget->capabilities.audio & AUDIO_CAP_AMPLIFIER_OVERRIDE) != 0) {
309 			verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
310 				VID_GET_PARAMETER, PID_OUTPUT_AMPLIFIER_CAP);
311 			status_t status = hda_send_verbs(audioGroup->codec, &verb,
312 				&response, 1);
313 			if (status < B_OK)
314 				return status;
315 
316 			widget->capabilities.output_amplifier = response;
317 		} else {
318 			// adopt capabilities from the audio function group
319 			widget->capabilities.output_amplifier
320 				= audioGroup->output_amplifier_capabilities;
321 		}
322 	}
323 
324 	if ((widget->capabilities.audio & AUDIO_CAP_INPUT_AMPLIFIER) != 0) {
325 		if ((widget->capabilities.audio & AUDIO_CAP_AMPLIFIER_OVERRIDE) != 0) {
326 			verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
327 				VID_GET_PARAMETER, PID_INPUT_AMPLIFIER_CAP);
328 			status_t status = hda_send_verbs(audioGroup->codec, &verb,
329 				&response, 1);
330 			if (status < B_OK)
331 				return status;
332 
333 			widget->capabilities.input_amplifier = response;
334 		} else {
335 			// adopt capabilities from the audio function group
336 			widget->capabilities.input_amplifier
337 				= audioGroup->input_amplifier_capabilities;
338 		}
339 	}
340 
341 	return B_OK;
342 }
343 
344 
345 static hda_widget*
346 hda_audio_group_get_widget(hda_audio_group* audioGroup, uint32 nodeID)
347 {
348 	if (audioGroup->widget_start > nodeID
349 		|| audioGroup->widget_start + audioGroup->widget_count < nodeID)
350 		return NULL;
351 
352 	return &audioGroup->widgets[nodeID - audioGroup->widget_start];
353 }
354 
355 
356 static status_t
357 hda_widget_get_connections(hda_audio_group* audioGroup, hda_widget* widget)
358 {
359 	uint32 verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
360 		VID_GET_PARAMETER, PID_CONNECTION_LIST_LENGTH);
361 	uint32 response;
362 
363 	if (hda_send_verbs(audioGroup->codec, &verb, &response, 1) != B_OK)
364 		return B_ERROR;
365 
366 	uint32 listEntries = response & 0x7f;
367 	bool longForm = (response & 0xf0) != 0;
368 
369 	if (listEntries == 0)
370 		return B_OK;
371 
372 #if 1
373 	if (widget->num_inputs > 1) {
374 		// Get currently active connection
375 		verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
376 			VID_GET_CONNECTION_SELECT, 0);
377 		if (hda_send_verbs(audioGroup->codec, &verb, &response, 1) == B_OK)
378 			widget->active_input = response & 0xff;
379 	}
380 #endif
381 
382 	uint32 valuesPerEntry = longForm ? 2 : 4;
383 	uint32 shift = 32 / valuesPerEntry;
384 	uint32 rangeMask = (1 << (shift - 1));
385 	int32 previousInput = -1;
386 	uint32 numInputs = 0;
387 
388 	for (uint32 i = 0; i < listEntries; i++) {
389 		if ((i % valuesPerEntry) == 0) {
390 			// We get 2 or 4 answers per call depending on if we're
391 			// in short or long list mode
392 			verb = MAKE_VERB(audioGroup->codec->addr, widget->node_id,
393 				VID_GET_CONNECTION_LIST_ENTRY, i);
394 			if (hda_send_verbs(audioGroup->codec, &verb, &response, 1)
395 					!= B_OK) {
396 				dprintf("hda: Error parsing inputs for widget %ld!\n",
397 					widget->node_id);
398 				break;
399 			}
400 		}
401 
402 		int32 input = (response >> (shift * (i % valuesPerEntry)))
403 			& ((1 << shift) - 1);
404 
405 		if (input & rangeMask) {
406 			// found range
407 			input &= ~rangeMask;
408 
409 			if (input < previousInput || previousInput == -1) {
410 				dprintf("hda: invalid range from %ld to %ld\n", previousInput,
411 					input);
412 				continue;
413 			}
414 
415 			for (int32 rangeInput = previousInput + 1; rangeInput <= input
416 					&& numInputs < MAX_INPUTS; rangeInput++) {
417 				widget->inputs[numInputs++] = rangeInput;
418 			}
419 
420 			previousInput = -1;
421 		} else if (numInputs < MAX_INPUTS) {
422 			// standard value
423 			widget->inputs[numInputs++] = input;
424 			previousInput = input;
425 		}
426 	}
427 
428 	widget->num_inputs = numInputs;
429 
430 	if (widget->num_inputs == 1)
431 		widget->active_input = 0;
432 
433 	return B_OK;
434 }
435 
436 
437 //	#pragma mark - audio group functions
438 
439 
440 static status_t
441 hda_codec_parse_audio_group(hda_audio_group* audioGroup)
442 {
443 	corb_t verbs[3];
444 	uint32 resp[3];
445 
446 	hda_get_stream_support(audioGroup->codec, audioGroup->root_node_id,
447 		&audioGroup->supported_formats, &audioGroup->supported_rates);
448 	hda_get_pm_support(audioGroup->codec, audioGroup->root_node_id,
449 		&audioGroup->supported_pm);
450 
451 	verbs[0] = MAKE_VERB(audioGroup->codec->addr, audioGroup->root_node_id,
452 		VID_GET_PARAMETER, PID_AUDIO_GROUP_CAP);
453 	verbs[1] = MAKE_VERB(audioGroup->codec->addr, audioGroup->root_node_id,
454 		VID_GET_PARAMETER, PID_GPIO_COUNT);
455 	verbs[2] = MAKE_VERB(audioGroup->codec->addr, audioGroup->root_node_id,
456 		VID_GET_PARAMETER, PID_SUB_NODE_COUNT);
457 
458 	if (hda_send_verbs(audioGroup->codec, verbs, resp, 3) != B_OK)
459 		return B_ERROR;
460 
461 	dprintf("hda: Audio Group: Output delay: %ld samples, Input delay: %ld "
462 		"samples, Beep Generator: %s\n", resp[0] & 0xf,
463 		(resp[0] >> 8) & 0xf, (resp[0] & (1 << 16)) ? "yes" : "no");
464 
465 	dprintf("hda:   #GPIO: %ld, #GPO: %ld, #GPI: %ld, unsol: %s, wake: %s\n",
466 		resp[4] & 0xff, (resp[1] >> 8) & 0xff,
467 		(resp[1] >> 16) & 0xff, (resp[1] & (1 << 30)) ? "yes" : "no",
468 		(resp[1] & (1 << 31)) ? "yes" : "no");
469 
470 	audioGroup->widget_start = resp[2] >> 16;
471 	audioGroup->widget_count = resp[2] & 0xff;
472 
473 	dprintf("hda:   widget start %lu, count %lu\n", audioGroup->widget_start,
474 		audioGroup->widget_count);
475 
476 	audioGroup->widgets = (hda_widget*)calloc(audioGroup->widget_count,
477 		sizeof(*audioGroup->widgets));
478 	if (audioGroup->widgets == NULL) {
479 		dprintf("ERROR: Not enough memory!\n");
480 		return B_NO_MEMORY;
481 	}
482 
483 	/* Iterate over all Widgets and collect info */
484 	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
485 		hda_widget& widget = audioGroup->widgets[i];
486 		uint32 nodeID = audioGroup->widget_start + i;
487 		uint32 capabilities;
488 
489 		verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID, VID_GET_PARAMETER,
490 			PID_AUDIO_WIDGET_CAP);
491 		if (hda_send_verbs(audioGroup->codec, verbs, &capabilities, 1) != B_OK)
492 			return B_ERROR;
493 
494 		widget.type = (hda_widget_type)((capabilities & AUDIO_CAP_TYPE_MASK)
495 			>> AUDIO_CAP_TYPE_SHIFT);
496 		widget.active_input = -1;
497 		widget.capabilities.audio = capabilities;
498 		widget.node_id = nodeID;
499 
500 		if ((capabilities & AUDIO_CAP_POWER_CONTROL) != 0) {
501 			/* We support power; switch us on! */
502 			verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
503 				VID_SET_POWER_STATE, 0);
504 			hda_send_verbs(audioGroup->codec, verbs, NULL, 1);
505 
506 			snooze(1000);
507 		}
508 		if ((capabilities & (AUDIO_CAP_INPUT_AMPLIFIER
509 				| AUDIO_CAP_OUTPUT_AMPLIFIER)) != 0) {
510 			hda_widget_get_amplifier_capabilities(audioGroup, &widget);
511 		}
512 
513 		dprintf("%ld: %s\n", nodeID, get_widget_type_name(widget.type));
514 
515 		switch (widget.type) {
516 			case WT_AUDIO_OUTPUT:
517 			case WT_AUDIO_INPUT:
518 				hda_widget_get_stream_support(audioGroup, &widget);
519 				break;
520 
521 			case WT_PIN_COMPLEX:
522 				verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
523 					VID_GET_PARAMETER, PID_PIN_CAP);
524 				if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) {
525 					widget.d.pin.input = resp[0] & PIN_CAP_IN;
526 					widget.d.pin.output = resp[0] & PIN_CAP_OUT;
527 
528 					dprintf("\t%s%s\n", widget.d.pin.input ? "[Input] " : "",
529 						widget.d.pin.output ? "[Output]" : "");
530 				} else {
531 					dprintf("%s: Error getting Pin Complex IO\n", __func__);
532 				}
533 
534 				verbs[0] = MAKE_VERB(audioGroup->codec->addr, nodeID,
535 					VID_GET_CONFIGURATION_DEFAULT, 0);
536 				if (hda_send_verbs(audioGroup->codec, verbs, resp, 1) == B_OK) {
537 					widget.d.pin.device = (pin_dev_type)
538 						((resp[0] >> 20) & 0xf);
539 					dprintf("\t%s, %s, %s, %s\n",
540 						kPortConnector[resp[0] >> 30],
541 						kDefaultDevice[widget.d.pin.device],
542 						kConnectionType[(resp[0] >> 16) & 0xF],
543 						kJackColor[(resp[0] >> 12) & 0xF]);
544 				}
545 				break;
546 
547 			default:
548 				break;
549 		}
550 
551 		hda_widget_get_pm_support(audioGroup, &widget);
552 		hda_widget_get_connections(audioGroup, &widget);
553 
554 		dump_widget_pm_support(widget);
555 		dump_widget_audio_capabilities(capabilities);
556 		dump_widget_amplifier_capabilities(widget, true);
557 		dump_widget_amplifier_capabilities(widget, false);
558 		dump_widget_inputs(widget);
559 	}
560 
561 	return B_OK;
562 }
563 
564 
565 /*! Find output path for widget */
566 static bool
567 hda_widget_find_output_path(hda_audio_group* audioGroup, hda_widget* widget,
568 	uint32 depth)
569 {
570 	if (widget == NULL || depth > 16)
571 		return false;
572 
573 	switch (widget->type) {
574 		case WT_AUDIO_OUTPUT:
575 			widget->flags |= WIDGET_FLAG_OUTPUT_PATH;
576 dprintf("      %*soutput: added output widget %ld\n", (int)depth * 2, "", widget->node_id);
577 			return true;
578 
579 		case WT_AUDIO_MIXER:
580 		case WT_AUDIO_SELECTOR:
581 		{
582 			// already used
583 			if (widget->flags & WIDGET_FLAG_OUTPUT_PATH)
584 				return false;
585 
586 			// search for output in this path
587 			bool found = false;
588 			for (uint32 i = 0; i < widget->num_inputs; i++) {
589 				hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup,
590 					widget->inputs[i]);
591 
592 				if (hda_widget_find_output_path(audioGroup, inputWidget,
593 						depth + 1)) {
594 					if (widget->active_input == -1)
595 						widget->active_input = i;
596 
597 					widget->flags |= WIDGET_FLAG_OUTPUT_PATH;
598 dprintf("      %*soutput: added mixer/selector widget %ld\n", (int)depth * 2, "", widget->node_id);
599 					found = true;
600 				}
601 			}
602 if (!found) dprintf("      %*soutput: not added mixer/selector widget %ld\n", (int)depth * 2, "", widget->node_id);
603 			return found;
604 		}
605 
606 		default:
607 			return false;
608 	}
609 }
610 
611 
612 /*! Find input path for widget */
613 static bool
614 hda_widget_find_input_path(hda_audio_group* audioGroup, hda_widget* widget,
615 	uint32 depth)
616 {
617 	if (widget == NULL || depth > 16)
618 		return false;
619 
620 	switch (widget->type) {
621 		case WT_PIN_COMPLEX:
622 			if (widget->d.pin.input
623 				&& (widget->d.pin.device == PIN_DEV_CD
624 					|| widget->d.pin.device == PIN_DEV_LINE_IN
625 					|| widget->d.pin.device == PIN_DEV_MIC_IN)) {
626 				widget->flags |= WIDGET_FLAG_INPUT_PATH;
627 dprintf("      %*sinput: added input widget %ld\n", (int)depth * 2, "", widget->node_id);
628 				return true;
629 			}
630 			return false;
631 		case WT_AUDIO_INPUT:
632 		case WT_AUDIO_MIXER:
633 		case WT_AUDIO_SELECTOR:
634 		{
635 			// already used
636 			if (widget->flags & WIDGET_FLAG_INPUT_PATH)
637 				return false;
638 
639 			// search for pin complex in this path
640 			bool found = false;
641 			for (uint32 i = 0; i < widget->num_inputs; i++) {
642 				hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup,
643 					widget->inputs[i]);
644 
645 				if (hda_widget_find_input_path(audioGroup, inputWidget,
646 						depth + 1)) {
647 					if (widget->active_input == -1)
648 						widget->active_input = i;
649 
650 					widget->flags |= WIDGET_FLAG_INPUT_PATH;
651 dprintf("      %*sinput: added mixer/selector widget %ld\n", (int)depth * 2, "", widget->node_id);
652 					found = true;
653 				}
654 			}
655 if (!found) dprintf("      %*sinput: not added mixer/selector widget %ld\n", (int)depth * 2, "", widget->node_id);
656 			return found;
657 		}
658 
659 		default:
660 			return false;
661 	}
662 }
663 
664 static bool
665 hda_audio_group_build_output_tree(hda_audio_group* audioGroup, bool useMixer)
666 {
667 	bool found = false;
668 
669 dprintf("build output tree: %suse mixer\n", useMixer ? "" : "don't ");
670 	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
671 		hda_widget& widget = audioGroup->widgets[i];
672 
673 		if (widget.type != WT_PIN_COMPLEX || !widget.d.pin.output
674 			|| (widget.d.pin.device != PIN_DEV_HEAD_PHONE_OUT
675 				&& widget.d.pin.device != PIN_DEV_SPEAKER
676 				&& widget.d.pin.device != PIN_DEV_LINE_OUT))
677 			continue;
678 
679 dprintf("  look at pin widget %ld (%ld inputs)\n", widget.node_id, widget.num_inputs);
680 		for (uint32 j = 0; j < widget.num_inputs; j++) {
681 			hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup,
682 				widget.inputs[j]);
683 dprintf("    try widget %ld: %p\n", widget.inputs[j], inputWidget);
684 			if (inputWidget == NULL)
685 				continue;
686 
687 			if (useMixer && inputWidget->type != WT_AUDIO_MIXER
688 				&& inputWidget->type != WT_AUDIO_SELECTOR)
689 				continue;
690 dprintf("    widget %ld is candidate\n", inputWidget->node_id);
691 
692 			if (hda_widget_find_output_path(audioGroup, inputWidget, 0)) {
693 dprintf("    add pin widget %ld\n", widget.node_id);
694 				if (widget.active_input == -1)
695 					widget.active_input = j;
696 				widget.flags |= WIDGET_FLAG_OUTPUT_PATH;
697 				found = true;
698 				break;
699 			}
700 		}
701 	}
702 
703 	return found;
704 }
705 
706 
707 static bool
708 hda_audio_group_build_input_tree(hda_audio_group* audioGroup)
709 {
710 	bool found = false;
711 
712 dprintf("build input tree\n");
713 	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
714 		hda_widget& widget = audioGroup->widgets[i];
715 
716 		if (widget.type != WT_AUDIO_INPUT)
717 			continue;
718 
719 dprintf("  look at input widget %ld (%ld inputs)\n", widget.node_id, widget.num_inputs);
720 		for (uint32 j = 0; j < widget.num_inputs; j++) {
721 			hda_widget* inputWidget = hda_audio_group_get_widget(audioGroup,
722 				widget.inputs[j]);
723 dprintf("    try widget %ld: %p\n", widget.inputs[j], inputWidget);
724 			if (inputWidget == NULL)
725 				continue;
726 
727 dprintf("    widget %ld is candidate\n", inputWidget->node_id);
728 
729 			if (hda_widget_find_input_path(audioGroup, inputWidget, 0)) {
730 dprintf("    add pin widget %ld\n", widget.node_id);
731 				if (widget.active_input == -1)
732 					widget.active_input = j;
733 				widget.flags |= WIDGET_FLAG_INPUT_PATH;
734 				found = true;
735 				break;
736 			}
737 		}
738 	}
739 
740 	return found;
741 }
742 
743 
744 static status_t
745 hda_audio_group_build_tree(hda_audio_group* audioGroup)
746 {
747 	if (!hda_audio_group_build_output_tree(audioGroup, true)) {
748 		// didn't find a mixer path, try again without
749 dprintf("try without mixer!\n");
750 		if (!hda_audio_group_build_output_tree(audioGroup, false))
751 			return ENODEV;
752 	}
753 
754 	if (!hda_audio_group_build_input_tree(audioGroup)) {
755 		dprintf("hda: build input tree failed\n");
756 	}
757 
758 dprintf("build tree!\n");
759 
760 	// select active connections
761 
762 	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
763 		hda_widget& widget = audioGroup->widgets[i];
764 
765 		if (widget.active_input == -1)
766 			widget.active_input = 0;
767 		if (widget.num_inputs < 2)
768 			continue;
769 
770 		corb_t verb = MAKE_VERB(audioGroup->codec->addr,
771 			widget.node_id, VID_SET_CONNECTION_SELECT, widget.active_input);
772 		if (hda_send_verbs(audioGroup->codec, &verb, NULL, 1) != B_OK) {
773 			dprintf("hda: Setting output selector %ld failed on widget %ld!\n",
774 				widget.active_input, widget.node_id);
775 		}
776 	}
777 
778 	dump_audiogroup_widgets(audioGroup);
779 
780 	return B_OK;
781 }
782 
783 
784 static void
785 hda_codec_delete_audio_group(hda_audio_group* audioGroup)
786 {
787 	if (audioGroup == NULL)
788 		return;
789 
790 	if (audioGroup->playback_stream != NULL)
791 		hda_stream_delete(audioGroup->playback_stream);
792 
793 	if (audioGroup->record_stream != NULL)
794 		hda_stream_delete(audioGroup->record_stream);
795 
796 	free(audioGroup->widgets);
797 	free(audioGroup);
798 }
799 
800 
801 static status_t
802 hda_codec_new_audio_group(hda_codec* codec, uint32 audioGroupNodeID)
803 {
804 	hda_audio_group* audioGroup = (hda_audio_group*)calloc(1,
805 		sizeof(hda_audio_group));
806 	if (audioGroup == NULL)
807 		return B_NO_MEMORY;
808 
809 	/* Setup minimal info needed by hda_codec_parse_afg */
810 	audioGroup->root_node_id = audioGroupNodeID;
811 	audioGroup->codec = codec;
812 
813 	/* Parse all widgets in Audio Function Group */
814 	status_t status = hda_codec_parse_audio_group(audioGroup);
815 	if (status != B_OK)
816 		goto err;
817 
818 	/* Setup for worst-case scenario; we cannot find any output Pin Widgets */
819 	status = ENODEV;
820 
821 	if (hda_audio_group_build_tree(audioGroup) != B_OK)
822 		goto err;
823 
824 	audioGroup->playback_stream = hda_stream_new(audioGroup, STREAM_PLAYBACK);
825 	audioGroup->record_stream = hda_stream_new(audioGroup, STREAM_RECORD);
826 	dprintf("hda: streams playback %p, record %p\n", audioGroup->playback_stream,
827 		audioGroup->record_stream);
828 
829 	if (audioGroup->playback_stream != NULL
830 		|| audioGroup->record_stream != NULL) {
831 		codec->audio_groups[codec->num_audio_groups++] = audioGroup;
832 		return B_OK;
833 	}
834 
835 err:
836 	free(audioGroup->widgets);
837 	free(audioGroup);
838 	return status;
839 }
840 
841 
842 //	#pragma mark -
843 
844 
845 status_t
846 hda_audio_group_get_widgets(hda_audio_group* audioGroup, hda_stream* stream)
847 {
848 	hda_widget_type type;
849 	uint32 flags;
850 
851 	if (stream->type == STREAM_PLAYBACK) {
852 		type = WT_AUDIO_OUTPUT;
853 		flags = WIDGET_FLAG_OUTPUT_PATH;
854 	} else {
855 		// record
856 		type = WT_AUDIO_INPUT;
857 		flags = WIDGET_FLAG_INPUT_PATH;
858 	}
859 
860 	uint32 count = 0;
861 
862 	for (uint32 i = 0; i < audioGroup->widget_count && count < MAX_IO_WIDGETS;
863 			i++) {
864 		hda_widget& widget = audioGroup->widgets[i];
865 
866 		if ((widget.flags & flags) != 0) {
867 			if (widget.type == WT_PIN_COMPLEX) {
868 				stream->pin_widget = widget.node_id;
869 
870 dprintf("ENABLE pin widget %ld\n", widget.node_id);
871 				/* FIXME: Force Pin Widget to unmute; enable hp/output */
872 				uint32 verb = MAKE_VERB(audioGroup->codec->addr,
873 					widget.node_id,
874 					VID_SET_PIN_WIDGET_CONTROL,
875 					flags == WIDGET_FLAG_OUTPUT_PATH ?
876 						PIN_ENABLE_HEAD_PHONE | PIN_ENABLE_OUTPUT
877 						: PIN_ENABLE_INPUT);
878 				hda_send_verbs(audioGroup->codec, &verb, NULL, 1);
879 			}
880 
881 			if (widget.capabilities.output_amplifier != 0) {
882 dprintf("UNMUTE/SET GAIN widget %ld (offset %ld)\n", widget.node_id,
883 	widget.capabilities.output_amplifier & AMP_CAP_OFFSET_MASK);
884 				uint32 verb = MAKE_VERB(audioGroup->codec->addr,
885 					widget.node_id,
886 					VID_SET_AMPLIFIER_GAIN_MUTE,
887 					AMP_SET_OUTPUT | AMP_SET_LEFT_CHANNEL
888 						| AMP_SET_RIGHT_CHANNEL
889 						| (widget.capabilities.output_amplifier
890 							& AMP_CAP_OFFSET_MASK));
891 				hda_send_verbs(audioGroup->codec, &verb, NULL, 1);
892 			}
893 		}
894 
895 		if (widget.type != type || (widget.flags & flags) == 0
896 			|| (widget.capabilities.audio
897 				& (AUDIO_CAP_STEREO | AUDIO_CAP_DIGITAL)) != AUDIO_CAP_STEREO
898 			|| widget.d.io.formats == 0)
899 			continue;
900 
901 		if (count == 0) {
902 			stream->sample_format = widget.d.io.formats;
903 			stream->sample_rate = widget.d.io.rates;
904 		} else {
905 			stream->sample_format &= widget.d.io.formats;
906 			stream->sample_rate &= widget.d.io.rates;
907 		}
908 
909 		stream->io_widgets[count++] = widget.node_id;
910 	}
911 
912 	if (count == 0)
913 		return B_ENTRY_NOT_FOUND;
914 
915 	stream->num_io_widgets = count;
916 	return B_OK;
917 }
918 
919 
920 void
921 hda_codec_delete(hda_codec* codec)
922 {
923 	if (codec == NULL)
924 		return;
925 
926 	delete_sem(codec->response_sem);
927 
928 	for (uint32 i = 0; i < codec->num_audio_groups; i++) {
929 		hda_codec_delete_audio_group(codec->audio_groups[i]);
930 		codec->audio_groups[i] = NULL;
931 	}
932 
933 	free(codec);
934 }
935 
936 
937 hda_codec*
938 hda_codec_new(hda_controller* controller, uint32 codecAddress)
939 {
940 	if (codecAddress > HDA_MAX_CODECS)
941 		return NULL;
942 
943 	hda_codec* codec = (hda_codec*)calloc(1, sizeof(hda_codec));
944 	if (codec == NULL)
945 		return NULL;
946 
947 	codec->controller = controller;
948 	codec->addr = codecAddress;
949 	codec->response_sem = create_sem(0, "hda_codec_response_sem");
950 	controller->codecs[codecAddress] = codec;
951 
952 	struct {
953 		uint32 device : 16;
954 		uint32 vendor : 16;
955 		uint32 stepping : 8;
956 		uint32 revision : 8;
957 		uint32 minor : 4;
958 		uint32 major : 4;
959 		uint32 _reserved0 : 8;
960 		uint32 count : 8;
961 		uint32 _reserved1 : 8;
962 		uint32 start : 8;
963 		uint32 _reserved2 : 8;
964 	} response;
965 	corb_t verbs[3];
966 
967 	verbs[0] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_VENDOR_ID);
968 	verbs[1] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER, PID_REVISION_ID);
969 	verbs[2] = MAKE_VERB(codecAddress, 0, VID_GET_PARAMETER,
970 		PID_SUB_NODE_COUNT);
971 
972 	if (hda_send_verbs(codec, verbs, (uint32*)&response, 3) != B_OK)
973 		goto err;
974 
975 	dprintf("Codec %ld Vendor: %04lx Product: %04lx, Revision: "
976 		"%lu.%lu.%lu.%lu\n", codecAddress, response.vendor, response.device,
977 		response.major, response.minor, response.revision, response.stepping);
978 
979 	for (uint32 nodeID = response.start; nodeID < response.start
980 			+ response.count; nodeID++) {
981 		uint32 groupType;
982 		verbs[0] = MAKE_VERB(codecAddress, nodeID, VID_GET_PARAMETER,
983 			PID_FUNCTION_GROUP_TYPE);
984 
985 		if (hda_send_verbs(codec, verbs, &groupType, 1) != B_OK)
986 			goto err;
987 
988 		if ((groupType & 0xff) == 1) {
989 			/* Found an Audio Function Group! */
990 			status_t status = hda_codec_new_audio_group(codec, nodeID);
991 			if (status != B_OK) {
992 				dprintf("hda: Failed to setup new audio function group (%s)!\n",
993 					strerror(status));
994 				goto err;
995 			}
996 		}
997 	}
998 
999 	return codec;
1000 
1001 err:
1002 	controller->codecs[codecAddress] = NULL;
1003 	hda_codec_delete(codec);
1004 	return NULL;
1005 }
1006