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