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