1/*
2 * Copyright 2007-2010, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Ithamar Adema, ithamar AT unet DOT nl
7 *		Axel D��rfler, axeld@pinc-software.de
8 */
9
10
11#include <driver_settings.h>
12
13#include "hmulti_audio.h"
14#include "driver.h"
15
16#include <kernel.h>
17
18
19#ifdef TRACE
20#	undef TRACE
21#endif
22
23//#define TRACE_MULTI_AUDIO
24#ifdef TRACE_MULTI_AUDIO
25#	define TRACE(a...) dprintf("hda: " a)
26#else
27#	define TRACE(a...) ;
28#endif
29#define ERROR(a...)	dprintf("hda: " a)
30
31typedef enum {
32	B_MIX_GAIN = 1 << 0,
33	B_MIX_MUTE = 1 << 1,
34	B_MIX_MUX_MIXER = 1 << 2,
35	B_MIX_MUX_SELECTOR = 1 << 3
36} mixer_type;
37
38
39static multi_channel_info sChannels[] = {
40	{  0, B_MULTI_OUTPUT_CHANNEL,	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
41	{  1, B_MULTI_OUTPUT_CHANNEL,	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
42	{  2, B_MULTI_INPUT_CHANNEL,	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
43	{  3, B_MULTI_INPUT_CHANNEL,	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
44	{  4, B_MULTI_OUTPUT_BUS,		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS,
45			B_CHANNEL_MINI_JACK_STEREO },
46	{  5, B_MULTI_OUTPUT_BUS,		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS,
47			B_CHANNEL_MINI_JACK_STEREO },
48	{  6, B_MULTI_INPUT_BUS,		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS,
49			B_CHANNEL_MINI_JACK_STEREO },
50	{  7, B_MULTI_INPUT_BUS,		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS,
51			B_CHANNEL_MINI_JACK_STEREO },
52};
53
54
55static int32
56format2size(uint32 format)
57{
58	switch (format) {
59		case B_FMT_8BIT_S:
60		case B_FMT_16BIT:
61			return 2;
62
63		case B_FMT_18BIT:
64		case B_FMT_20BIT:
65		case B_FMT_24BIT:
66		case B_FMT_32BIT:
67		case B_FMT_FLOAT:
68			return 4;
69
70		default:
71			return -1;
72	}
73}
74
75
76#define HDA_SETTINGS "hda.settings"
77
78static struct {
79	int32 play_buffer_frames;
80	int32 play_buffer_count;
81	int32 record_buffer_frames;
82	int32 record_buffer_count;
83} requested_settings;
84
85
86void
87get_settings_from_file()
88{
89	const char *item;
90	char       *end;
91	uint32      value;
92
93	memset(&requested_settings, 0, sizeof(requested_settings));
94	dprintf("looking for settings file\n");
95
96	void *settings_handle = load_driver_settings(HDA_SETTINGS);
97	if (settings_handle == NULL)
98		return;
99
100	item = get_driver_parameter (settings_handle, "play_buffer_frames", NULL,
101		NULL);
102	if (item) {
103		value = strtoul (item, &end, 0);
104		if (*end == '\0')
105			requested_settings.play_buffer_frames = value;
106		}
107
108	item = get_driver_parameter (settings_handle, "play_buffer_count", NULL,
109		NULL);
110	if (item) {
111		value = strtoul (item, &end, 0);
112		if (*end == '\0')
113			requested_settings.play_buffer_count = value;
114	}
115
116	item = get_driver_parameter (settings_handle, "record_buffer_frames", NULL,
117		NULL);
118	if (item) {
119		value = strtoul (item, &end, 0);
120		if (*end == '\0')
121			requested_settings.record_buffer_frames = value;
122	}
123
124	item = get_driver_parameter (settings_handle, "record_buffer_count", NULL,
125		NULL);
126	if (item) {
127		value = strtoul (item, &end, 0);
128		if (*end == '\0')
129			requested_settings.record_buffer_count = value;
130	}
131
132	unload_driver_settings(settings_handle);
133}
134
135
136static status_t
137get_description(hda_audio_group* audioGroup, multi_description* data)
138{
139	data->interface_version = B_CURRENT_INTERFACE_VERSION;
140	data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
141
142	strcpy(data->friendly_name, "HD Audio");
143	strcpy(data->vendor_info, "Haiku");
144
145	int32 inChannels = 0;
146	if (audioGroup->record_stream != NULL)
147		inChannels = 2;
148
149	int32 outChannels = 0;
150	if (audioGroup->playback_stream != NULL)
151		outChannels = 2;
152
153	data->output_channel_count = outChannels;
154	data->output_bus_channel_count = outChannels;
155	data->input_channel_count = inChannels;
156	data->input_bus_channel_count = inChannels;
157	data->aux_bus_channel_count = 0;
158
159	TRACE("%s: request_channel_count: %" B_PRId32 "\n", __func__,
160		data->request_channel_count);
161
162	if (data->request_channel_count >= (int)(sizeof(sChannels)
163			/ sizeof(sChannels[0]))) {
164		memcpy(data->channels, &sChannels, sizeof(sChannels));
165	}
166
167	if (audioGroup->playback_stream != NULL) {
168		data->output_rates = audioGroup->playback_stream->sample_rate;
169		data->output_formats = audioGroup->playback_stream->sample_format;
170	} else {
171		data->output_rates = 0;
172		data->output_formats = 0;
173	}
174
175	if (audioGroup->record_stream != NULL) {
176		data->input_rates = audioGroup->record_stream->sample_rate;
177		data->input_formats = audioGroup->record_stream->sample_format;
178	} else {
179		data->input_rates = 0;
180		data->input_formats = 0;
181	}
182
183	// force existance of 48kHz if variable rates are not supported
184	if (data->output_rates == 0)
185		data->output_rates = B_SR_48000;
186	if (data->input_rates == 0)
187		data->input_rates = B_SR_48000;
188
189	data->max_cvsr_rate = 0;
190	data->min_cvsr_rate = 0;
191
192	data->lock_sources = B_MULTI_LOCK_INTERNAL;
193	data->timecode_sources = 0;
194	data->interface_flags
195		= B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
196	data->start_latency = 30000;
197
198	strcpy(data->control_panel, "");
199
200	return B_OK;
201}
202
203
204static status_t
205get_enabled_channels(hda_audio_group* audioGroup, multi_channel_enable* data)
206{
207	data->lock_source = B_MULTI_LOCK_INTERNAL;
208
209	int32 inChannels = 0;
210	if (audioGroup->record_stream != NULL)
211		inChannels = 2;
212
213	int32 outChannels = 0;
214	if (audioGroup->playback_stream != NULL)
215		outChannels = 2;
216
217	uint32 enable_bits = 0;
218	uint32 maxChannels = min_c(32, inChannels + outChannels);
219	for (uint32 i = 0; i < maxChannels; i++)
220		B_SET_CHANNEL(&enable_bits, i, true);
221
222	return B_OK;
223}
224
225
226static status_t
227get_global_format(hda_audio_group* audioGroup, multi_format_info* data)
228{
229	data->output_latency = 0;
230	data->input_latency = 0;
231	data->timecode_kind = 0;
232
233	if (audioGroup->playback_stream != NULL) {
234		data->output.format = audioGroup->playback_stream->sample_format;
235		data->output.rate = audioGroup->playback_stream->sample_rate;
236	} else {
237		data->output.format = 0;
238		data->output.rate = 0;
239	}
240
241	if (audioGroup->record_stream != NULL) {
242		data->input.format = audioGroup->record_stream->sample_format;
243		data->input.rate = audioGroup->record_stream->sample_rate;
244	} else {
245		data->input.format = 0;
246		data->input.rate = 0;
247	}
248
249	return B_OK;
250}
251
252
253static status_t
254set_global_format(hda_audio_group* audioGroup, multi_format_info* data)
255{
256	// TODO: it looks like we're not supposed to fail; fix this!
257#if 0
258	if ((data->output.format & audioGroup->supported_formats) == 0)
259		|| (data->output.rate & audioGroup->supported_rates) == 0)
260		return B_BAD_VALUE;
261#endif
262
263	if (audioGroup->playback_stream != NULL) {
264		audioGroup->playback_stream->sample_format = data->output.format;
265		audioGroup->playback_stream->sample_rate = data->output.rate;
266		audioGroup->playback_stream->sample_size = format2size(
267			audioGroup->playback_stream->sample_format);
268	}
269
270	if (audioGroup->record_stream != NULL) {
271		audioGroup->record_stream->sample_rate = data->input.rate;
272		audioGroup->record_stream->sample_format = data->input.format;
273		audioGroup->record_stream->sample_size = format2size(
274			audioGroup->record_stream->sample_format);
275	}
276
277	return B_OK;
278}
279
280
281static enum strind_id
282hda_find_multi_string(hda_widget& widget)
283{
284	switch (CONF_DEFAULT_DEVICE(widget.d.pin.config)) {
285		case PIN_DEV_CD:
286			return S_CD;
287		case PIN_DEV_LINE_IN:
288		case PIN_DEV_LINE_OUT:
289			return S_LINE;
290		case PIN_DEV_MIC_IN:
291			return S_MIC;
292		case PIN_DEV_AUX:
293			return S_AUX;
294		case PIN_DEV_SPDIF_IN:
295		case PIN_DEV_SPDIF_OUT:
296			return S_SPDIF;
297		case PIN_DEV_HEAD_PHONE_OUT:
298			return S_HEADPHONE;
299	}
300	ERROR("couln't find a string for widget %" B_PRIu32 " in "
301		"hda_find_multi_string()\n", widget.node_id);
302	return S_null;
303}
304
305
306static void
307hda_find_multi_custom_string(hda_widget& widget, char* custom, uint32 size)
308{
309	const char* device = NULL;
310	switch (CONF_DEFAULT_DEVICE(widget.d.pin.config)) {
311		case PIN_DEV_LINE_IN:
312			device = "Line in";
313		case PIN_DEV_LINE_OUT:
314			if (device == NULL)
315				device = "Line out";
316		case PIN_DEV_MIC_IN:
317			if (device == NULL)
318				device =  "Mic in";
319			switch (CONF_DEFAULT_COLOR(widget.d.pin.config)) {
320				case 1:
321					device = "Rear";
322					break;
323				case 2:
324					device = "Side";
325					break;
326				case 3:
327					device = "Line in";
328					break;
329				case 4:
330					device = "Front";
331					break;
332				case 6:
333					device = "Center/Sub";
334					break;
335				case 9:
336					device = "Mic in";
337					break;
338			}
339			break;
340		case PIN_DEV_SPDIF_IN:
341			device = "SPDIF in";
342			break;
343		case PIN_DEV_SPDIF_OUT:
344			device = "SPDIF out";
345			break;
346		case PIN_DEV_CD:
347			device = "CD";
348			break;
349		case PIN_DEV_HEAD_PHONE_OUT:
350			device = "Headphones";
351			break;
352		case PIN_DEV_SPEAKER:
353			device = "Speaker";
354			break;
355	}
356	if (device == NULL) {
357		ERROR("couldn't find a string for widget %" B_PRIu32 " in "
358			"hda_find_multi_custom_string()\n", widget.node_id);
359	}
360
361	const char* location
362		= get_widget_location(CONF_DEFAULT_LOCATION(widget.d.pin.config));
363	snprintf(custom, size, "%s%s%s", location ? location : "",
364		location ? " " : "", device);
365}
366
367
368static int32
369hda_create_group_control(hda_multi *multi, uint32 *index, int32 parent,
370	enum strind_id string, const char* name)
371{
372	uint32 i = *index;
373	(*index)++;
374	multi->controls[i].mix_control.id = MULTI_CONTROL_FIRSTID + i;
375	multi->controls[i].mix_control.parent = parent;
376	multi->controls[i].mix_control.flags = B_MULTI_MIX_GROUP;
377	multi->controls[i].mix_control.master = MULTI_CONTROL_MASTERID;
378	multi->controls[i].mix_control.string = string;
379	if (name)
380		strcpy(multi->controls[i].mix_control.name, name);
381
382	return multi->controls[i].mix_control.id;
383}
384
385
386static void
387hda_create_channel_control(hda_multi* multi, uint32* index, int32 parent,
388	int32 string, hda_widget& widget, bool input, uint32 capabilities,
389	int32 inputIndex, bool& gain, bool& mute)
390{
391	uint32 i = *index, id;
392	hda_multi_mixer_control control;
393
394	control.nid = widget.node_id;
395	control.input = input;
396	control.mute = 0;
397	control.gain = 0;
398	control.capabilities = capabilities;
399	control.index = inputIndex;
400	control.mix_control.master = MULTI_CONTROL_MASTERID;
401	control.mix_control.parent = parent;
402
403	if (mute && (capabilities & AMP_CAP_MUTE) != 0) {
404		control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
405		control.mix_control.flags = B_MULTI_MIX_ENABLE;
406		control.mix_control.string = S_MUTE;
407		control.type = B_MIX_MUTE;
408		multi->controls[i++] = control;
409		TRACE("control nid %" B_PRIu32 " mute\n", control.nid);
410		mute = false;
411	}
412
413	if (gain && AMP_CAP_NUM_STEPS(capabilities) >= 1) {
414		control.mix_control.gain.granularity = AMP_CAP_STEP_SIZE(capabilities);
415		control.mix_control.gain.min_gain = (0.0 - AMP_CAP_OFFSET(capabilities))
416			* control.mix_control.gain.granularity;
417		control.mix_control.gain.max_gain = (AMP_CAP_NUM_STEPS(capabilities)
418				- AMP_CAP_OFFSET(capabilities))
419			* control.mix_control.gain.granularity;
420
421		control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
422		control.mix_control.flags = B_MULTI_MIX_GAIN;
423		control.mix_control.string = S_null;
424		control.type = B_MIX_GAIN;
425		strcpy(control.mix_control.name, "Gain");
426		multi->controls[i++] = control;
427		id = control.mix_control.id;
428
429		// second channel
430		control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
431		control.mix_control.master = id;
432		multi->controls[i++] = control;
433		TRACE("control nid %" B_PRIu32 " %f min %f max %f\n", control.nid,
434			control.mix_control.gain.granularity,
435			control.mix_control.gain.min_gain,
436			control.mix_control.gain.max_gain);
437		gain = false;
438	}
439
440	*index = i;
441}
442
443
444static void
445hda_create_mux_control(hda_multi *multi, uint32 *index, int32 parent,
446	hda_widget& widget)
447{
448	uint32 i = *index, parent2;
449	hda_multi_mixer_control control;
450	hda_audio_group *audioGroup = multi->group;
451
452	control.nid = widget.node_id;
453	control.input = true;
454	control.mute = 0;
455	control.gain = 0;
456	control.mix_control.master = MULTI_CONTROL_MASTERID;
457	control.mix_control.parent = parent;
458	control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
459	control.mix_control.flags = B_MULTI_MIX_MUX;
460	control.mix_control.string = S_null;
461	control.type = widget.type == WT_AUDIO_MIXER
462		? B_MIX_MUX_MIXER : B_MIX_MUX_SELECTOR;
463	multi->controls[i] = control;
464	strcpy(multi->controls[i].mix_control.name, "");
465	i++;
466	parent2 = control.mix_control.id;
467
468	for (uint32 j = 0; j < widget.num_inputs; j++) {
469		hda_widget *input =
470			hda_audio_group_get_widget(audioGroup, widget.inputs[j]);
471		if (input->type != WT_PIN_COMPLEX)
472			continue;
473		control.nid = widget.node_id;
474		control.input = true;
475		control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
476		control.mix_control.flags = B_MULTI_MIX_MUX_VALUE;
477		control.mix_control.parent = parent2;
478		control.mix_control.string = S_null;
479		multi->controls[i] = control;
480		hda_find_multi_custom_string(*input,
481			multi->controls[i].mix_control.name,
482			sizeof(multi->controls[i].mix_control.name));
483		i++;
484	}
485
486	*index = i;
487}
488
489
490static void
491hda_create_control_for_complex(hda_multi* multi, uint32* index, uint32 parent,
492	hda_widget& widget, bool& gain, bool& mute)
493{
494	hda_audio_group* audioGroup = multi->group;
495
496	switch (widget.type) {
497		case WT_AUDIO_OUTPUT:
498		case WT_AUDIO_MIXER:
499		case WT_AUDIO_SELECTOR:
500		case WT_PIN_COMPLEX:
501			break;
502		default:
503			return;
504	}
505
506	if ((widget.flags & WIDGET_FLAG_WIDGET_PATH) != 0)
507		return;
508
509	TRACE("  create widget nid %" B_PRIu32 "\n", widget.node_id);
510	hda_create_channel_control(multi, index, parent, 0,
511		widget, false, widget.capabilities.output_amplifier, 0, gain, mute);
512
513	if (!gain && !mute) {
514		widget.flags |= WIDGET_FLAG_WIDGET_PATH;
515		return;
516	}
517
518	if (widget.type == WT_AUDIO_MIXER) {
519		hda_create_channel_control(multi, index, parent, 0,
520			widget, true, widget.capabilities.input_amplifier, 0, gain, mute);
521		if (!gain && !mute) {
522			widget.flags |= WIDGET_FLAG_WIDGET_PATH;
523			return;
524		}
525	}
526
527	if (widget.type != WT_AUDIO_OUTPUT && widget.num_inputs > 0) {
528		hda_widget& child = *hda_audio_group_get_widget(audioGroup,
529			widget.inputs[widget.active_input]);
530		hda_create_control_for_complex(multi, index, parent, child, gain, mute);
531	}
532
533	widget.flags |= WIDGET_FLAG_WIDGET_PATH;
534}
535
536
537static status_t
538hda_create_controls_list(hda_multi* multi)
539{
540	uint32 index = 0;
541	hda_audio_group* audioGroup = multi->group;
542
543	uint32 parent = hda_create_group_control(multi, &index, 0, S_OUTPUT, NULL);
544	uint32 parent2;
545
546	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
547		hda_widget& complex = audioGroup->widgets[i];
548		char name[48];
549
550		if (complex.type != WT_PIN_COMPLEX)
551			continue;
552		if (!PIN_CAP_IS_OUTPUT(complex.d.pin.capabilities))
553			continue;
554		if ((complex.flags & WIDGET_FLAG_OUTPUT_PATH) == 0)
555			continue;
556
557		TRACE("create complex nid %" B_PRIu32 "\n", complex.node_id);
558		hda_find_multi_custom_string(complex, name, sizeof(name));
559		parent2 = hda_create_group_control(multi, &index, parent, S_null, name);
560		bool gain = true, mute = true;
561
562		hda_create_control_for_complex(multi, &index, parent2, complex, gain,
563			mute);
564	}
565
566	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
567		hda_widget& widget = audioGroup->widgets[i];
568
569		if (widget.type != WT_AUDIO_MIXER)
570			continue;
571		if ((widget.flags & WIDGET_FLAG_WIDGET_PATH) != 0)
572			continue;
573
574		TRACE("create widget nid %" B_PRIu32 "\n", widget.node_id);
575
576		if (AMP_CAP_NUM_STEPS(widget.capabilities.input_amplifier) >= 1) {
577			for (uint32 j = 0; j < widget.num_inputs; j++) {
578				hda_widget* complex = hda_audio_group_get_widget(audioGroup,
579					widget.inputs[j]);
580				char name[48];
581				if (complex->type != WT_PIN_COMPLEX)
582					continue;
583				if (!PIN_CAP_IS_INPUT(complex->d.pin.capabilities))
584					continue;
585				if ((complex->flags & WIDGET_FLAG_OUTPUT_PATH) != 0)
586					continue;
587				TRACE("  create widget input nid %" B_PRIu32 "\n",
588					widget.inputs[j]);
589				hda_find_multi_custom_string(*complex, name, sizeof(name));
590				parent2 = hda_create_group_control(multi, &index,
591					parent, S_null, name);
592				bool gain = true, mute = true;
593				hda_create_channel_control(multi, &index, parent2, 0, widget,
594					true, widget.capabilities.input_amplifier, j, gain, mute);
595			}
596		}
597
598		widget.flags |= WIDGET_FLAG_WIDGET_PATH;
599	}
600
601	parent = hda_create_group_control(multi, &index, 0, S_INPUT, NULL);
602
603	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
604		hda_widget& widget = audioGroup->widgets[i];
605
606		if (widget.type != WT_AUDIO_INPUT)
607			continue;
608
609		uint32 capabilities = widget.capabilities.input_amplifier;
610		if (AMP_CAP_NUM_STEPS(capabilities) < 1)
611			continue;
612
613		parent2 = hda_create_group_control(multi, &index,
614			parent, hda_find_multi_string(widget), "Input");
615		bool gain = true, mute = true;
616		hda_create_channel_control(multi, &index, parent2, 0,
617			widget, true, capabilities, 0, gain, mute);
618
619		if (widget.num_inputs > 1) {
620			TRACE("  create mux for nid %" B_PRIu32 "\n", widget.node_id);
621			hda_create_mux_control(multi, &index, parent2, widget);
622			continue;
623		}
624
625		hda_widget *mixer = hda_audio_group_get_widget(audioGroup,
626			widget.inputs[0]);
627		if (mixer->type != WT_AUDIO_MIXER && mixer->type != WT_AUDIO_SELECTOR)
628			continue;
629		TRACE("  create mixer nid %" B_PRIu32 "\n", mixer->node_id);
630		hda_create_mux_control(multi, &index, parent2, *mixer);
631	}
632
633	multi->control_count = index;
634	TRACE("multi->control_count %" B_PRIu32 "\n", multi->control_count);
635	return B_OK;
636}
637
638
639static status_t
640list_mix_controls(hda_audio_group* audioGroup, multi_mix_control_info* mmci)
641{
642	multi_mix_control *mmc = mmci->controls;
643	if (mmci->control_count < 24)
644		return B_ERROR;
645
646	if (hda_create_controls_list(audioGroup->multi) < B_OK)
647		return B_ERROR;
648	for (uint32 i = 0; i < audioGroup->multi->control_count; i++) {
649		mmc[i] = audioGroup->multi->controls[i].mix_control;
650	}
651
652	mmci->control_count = audioGroup->multi->control_count;
653	return B_OK;
654}
655
656
657static status_t
658list_mix_connections(hda_audio_group* audioGroup,
659	multi_mix_connection_info* data)
660{
661	data->actual_count = 0;
662	return B_OK;
663}
664
665
666static status_t
667list_mix_channels(hda_audio_group* audioGroup, multi_mix_channel_info *data)
668{
669	return B_OK;
670}
671
672
673static void
674get_control_gain_mute(hda_audio_group* audioGroup,
675	hda_multi_mixer_control *control, uint32 *resp)
676{
677	uint32 verb[2];
678	verb[0] = MAKE_VERB(audioGroup->codec->addr,
679		control->nid,
680		VID_GET_AMPLIFIER_GAIN_MUTE,
681		(control->input ? AMP_GET_INPUT : AMP_GET_OUTPUT)
682		| AMP_GET_LEFT_CHANNEL | AMP_GET_INPUT_INDEX(control->index));
683	verb[1] = MAKE_VERB(audioGroup->codec->addr,
684		control->nid,
685		VID_GET_AMPLIFIER_GAIN_MUTE,
686		(control->input ? AMP_GET_INPUT : AMP_GET_OUTPUT)
687		| AMP_GET_RIGHT_CHANNEL | AMP_GET_INPUT_INDEX(control->index));
688	hda_send_verbs(audioGroup->codec, verb, resp, 2);
689}
690
691
692static status_t
693get_mix(hda_audio_group* audioGroup, multi_mix_value_info * mmvi)
694{
695	int32 id;
696	hda_multi_mixer_control *control = NULL;
697	for (int32 i = 0; i < mmvi->item_count; i++) {
698		id = mmvi->values[i].id - MULTI_CONTROL_FIRSTID;
699		if (id < 0 || id >= (int32)audioGroup->multi->control_count) {
700			dprintf("hda: get_mix : invalid control id requested : %" B_PRId32
701				"\n", id);
702			continue;
703		}
704		control = &audioGroup->multi->controls[id];
705
706		if ((control->mix_control.flags
707				& (B_MULTI_MIX_GAIN | B_MULTI_MIX_ENABLE)) != 0) {
708			uint32 resp[2];
709			get_control_gain_mute(audioGroup, control, resp);
710			if ((control->mix_control.flags & B_MULTI_MIX_ENABLE) != 0) {
711				mmvi->values[i].enable = (resp[0] & AMP_MUTE) != 0;
712				TRACE("get_mix: %" B_PRId32 " mute: %d\n", control->nid,
713					mmvi->values[i].enable);
714			} else if ((control->mix_control.flags & B_MULTI_MIX_GAIN) != 0) {
715				uint32 value;
716				if (control->mix_control.master == MULTI_CONTROL_MASTERID)
717					value = resp[0] & AMP_GAIN_MASK;
718				else
719					value = resp[1] & AMP_GAIN_MASK;
720				mmvi->values[i].gain = (0.0 + value - AMP_CAP_OFFSET(control->capabilities))
721						* AMP_CAP_STEP_SIZE(control->capabilities);
722				TRACE("get_mix: %" B_PRId32 " gain: %f (%" B_PRIu32 ")\n",
723					control->nid, mmvi->values[i].gain, value);
724			}
725
726		} else if ((control->mix_control.flags & B_MIX_MUX_MIXER) != 0) {
727			hda_widget* mixer = hda_audio_group_get_widget(audioGroup,
728				control->nid);
729			mmvi->values[i].mux = 0;
730			for (uint32 j = 0; j < mixer->num_inputs; j++) {
731				uint32 verb = MAKE_VERB(audioGroup->codec->addr,
732					control->nid, VID_GET_AMPLIFIER_GAIN_MUTE, AMP_GET_INPUT
733					| AMP_GET_LEFT_CHANNEL | AMP_GET_INPUT_INDEX(j));
734				uint32 resp;
735				if (hda_send_verbs(audioGroup->codec, &verb, &resp, 1) == B_OK) {
736					TRACE("get_mix: %" B_PRId32 " mixer %" B_PRIu32
737						" is %smute\n", control->nid,
738						j, (resp & AMP_MUTE) != 0 ? "" : "un");
739					if ((resp & AMP_MUTE) == 0) {
740						mmvi->values[i].mux = j;
741#ifndef TRACE_MULTI_AUDIO
742						break;
743#endif
744					}
745				}
746			}
747			TRACE("get_mix: %" B_PRId32 " mixer: %" B_PRIu32 "\n",
748				control->nid, mmvi->values[i].mux);
749		} else if ((control->mix_control.flags & B_MIX_MUX_SELECTOR) != 0) {
750			uint32 verb = MAKE_VERB(audioGroup->codec->addr, control->nid,
751				VID_GET_CONNECTION_SELECT, 0);
752			uint32 resp;
753			if (hda_send_verbs(audioGroup->codec, &verb, &resp, 1) == B_OK)
754				mmvi->values[i].mux = resp & 0xff;
755			TRACE("get_mix: %" B_PRId32 " selector: %" B_PRIu32 "\n",
756				control->nid, mmvi->values[i].mux);
757		}
758	}
759	return B_OK;
760}
761
762
763static status_t
764set_mix(hda_audio_group* audioGroup, multi_mix_value_info * mmvi)
765{
766	int32 id;
767	hda_multi_mixer_control *control = NULL;
768	for (int32 i = 0; i < mmvi->item_count; i++) {
769		id = mmvi->values[i].id - MULTI_CONTROL_FIRSTID;
770		if (id < 0 || id >= (int32)audioGroup->multi->control_count) {
771			dprintf("set_mix : invalid control id requested : %" B_PRId32 "\n",
772				id);
773			continue;
774		}
775		control = &audioGroup->multi->controls[id];
776
777		if ((control->mix_control.flags & B_MULTI_MIX_ENABLE) != 0) {
778			control->mute = (mmvi->values[i].enable ? AMP_MUTE : 0);
779			TRACE("set_mix: %" B_PRId32 " mute: %" B_PRIx32 "\n", control->nid,
780				control->mute);
781			uint32 resp[2];
782			get_control_gain_mute(audioGroup, control, resp);
783
784			uint32 verb[2];
785			verb[0] = MAKE_VERB(audioGroup->codec->addr,
786				control->nid,
787				VID_SET_AMPLIFIER_GAIN_MUTE,
788				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
789				| AMP_SET_LEFT_CHANNEL
790				| AMP_SET_INPUT_INDEX(control->index)
791				| control->mute
792				| (resp[0] & AMP_GAIN_MASK));
793			TRACE("set_mix: sending verb to %" B_PRId32 ": %" B_PRIx32 " %"
794				B_PRIx32 " %x %lx\n", control->nid,
795				control->mute, resp[0] & AMP_GAIN_MASK, control->input,
796				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
797				| AMP_SET_LEFT_CHANNEL
798				| AMP_SET_INPUT_INDEX(control->index)
799				| control->mute
800				| (resp[0] & AMP_GAIN_MASK));
801			verb[1] = MAKE_VERB(audioGroup->codec->addr,
802				control->nid,
803				VID_SET_AMPLIFIER_GAIN_MUTE,
804				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
805				| AMP_SET_RIGHT_CHANNEL
806				| AMP_SET_INPUT_INDEX(control->index)
807				| control->mute
808				| (resp[1] & AMP_GAIN_MASK));
809			TRACE("set_mix: ctrl2 sending verb to %" B_PRId32 ": %" B_PRIx32
810				" %" B_PRIx32 " %x\n", control->nid, control->mute,
811				resp[1] & AMP_GAIN_MASK, control->input);
812			hda_send_verbs(audioGroup->codec, verb, NULL, 2);
813		} else if ((control->mix_control.flags & B_MULTI_MIX_GAIN) != 0) {
814			hda_multi_mixer_control *control2 = NULL;
815			if (i+1<mmvi->item_count) {
816				id = mmvi->values[i + 1].id - MULTI_CONTROL_FIRSTID;
817				if (id < 0 || id >= (int32)audioGroup->multi->control_count) {
818					dprintf("set_mix : invalid control id requested : %"
819						B_PRId32 "\n", id);
820				} else {
821					control2 = &audioGroup->multi->controls[id];
822					if (control2->mix_control.master != control->mix_control.id)
823						control2 = NULL;
824				}
825			}
826
827			if (control->mix_control.master == MULTI_CONTROL_MASTERID) {
828				control->gain = (uint32)(mmvi->values[i].gain
829					/ AMP_CAP_STEP_SIZE(control->capabilities)
830					+ AMP_CAP_OFFSET(control->capabilities));
831			}
832
833			if (control2
834				&& control2->mix_control.master != MULTI_CONTROL_MASTERID) {
835				control2->gain = (uint32)(mmvi->values[i+1].gain
836					/ AMP_CAP_STEP_SIZE(control2->capabilities)
837					+ AMP_CAP_OFFSET(control2->capabilities));
838			}
839			TRACE("set_mix: %" B_PRId32 " gain: %" B_PRIx32 " and %" B_PRId32
840				" gain: %" B_PRIx32 "\n", control->nid, control->gain,
841				control2->nid, control2->gain);
842			uint32 resp[2];
843			get_control_gain_mute(audioGroup, control, resp);
844			control->mute = resp[0] & AMP_MUTE;
845			if (control2)
846				control2->mute = resp[1] & AMP_MUTE;
847
848			uint32 verb[2];
849			verb[0] = MAKE_VERB(audioGroup->codec->addr,
850				control->nid,
851				VID_SET_AMPLIFIER_GAIN_MUTE,
852				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
853				| AMP_SET_LEFT_CHANNEL
854				| AMP_SET_INPUT_INDEX(control->index)
855				| (control->mute & AMP_MUTE)
856				| (control->gain & AMP_GAIN_MASK));
857			TRACE("set_mix: sending verb to %" B_PRId32 ": %" B_PRIx32 " %"
858				B_PRIx32 " %x %lx\n", control->nid,
859				control->mute, control->gain, control->input,
860				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
861				| AMP_SET_LEFT_CHANNEL
862				| AMP_SET_INPUT_INDEX(control->index)
863				| (control->mute & AMP_MUTE)
864				| (control->gain & AMP_GAIN_MASK));
865			if (control2) {
866				verb[1] = MAKE_VERB(audioGroup->codec->addr,
867					control2->nid,
868					VID_SET_AMPLIFIER_GAIN_MUTE,
869					(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
870					| AMP_SET_RIGHT_CHANNEL
871					| AMP_SET_INPUT_INDEX(control->index)
872					| (control2->mute & AMP_MUTE)
873					| (control2->gain & AMP_GAIN_MASK));
874				TRACE("set_mix: ctrl2 sending verb to %" B_PRId32 ": %"
875					B_PRIx32 " %" B_PRIx32 " %x\n", control2->nid,
876					control2->mute, control2->gain, control2->input);
877			}
878			hda_send_verbs(audioGroup->codec, verb, NULL, control2 ? 2 : 1);
879
880			if (control2)
881				i++;
882		} else if ((control->mix_control.flags & B_MIX_MUX_MIXER) != 0) {
883			TRACE("set_mix: %" B_PRId32 " mixer: %" B_PRIu32 "\n",
884				control->nid, mmvi->values[i].mux);
885			hda_widget *mixer = hda_audio_group_get_widget(audioGroup,
886				control->nid);
887			uint32 verb[mixer->num_inputs];
888			for (uint32 j = 0; j < mixer->num_inputs; j++) {
889				verb[j] = MAKE_VERB(audioGroup->codec->addr,
890					control->nid, VID_SET_AMPLIFIER_GAIN_MUTE, AMP_SET_INPUT
891					| AMP_SET_LEFT_CHANNEL | AMP_SET_RIGHT_CHANNEL
892					| AMP_SET_INPUT_INDEX(j)
893					| ((mmvi->values[i].mux == j) ? 0 : AMP_MUTE));
894				TRACE("set_mix: %" B_PRId32 " mixer %smuting %" B_PRIu32 " (%"
895					B_PRIu32 ")\n", control->nid,
896					(mmvi->values[i].mux == j) ? "un" : "", j, verb[j]);
897			}
898			if (hda_send_verbs(audioGroup->codec, verb, NULL, mixer->num_inputs)
899				!= B_OK)
900				dprintf("hda: Setting mixer %" B_PRId32 " failed on widget %"
901					B_PRIu32 "!\n", mmvi->values[i].mux, control->nid);
902		} else if ((control->mix_control.flags & B_MIX_MUX_SELECTOR) != 0) {
903			uint32 verb = MAKE_VERB(audioGroup->codec->addr, control->nid,
904				VID_SET_CONNECTION_SELECT, mmvi->values[i].mux);
905			if (hda_send_verbs(audioGroup->codec, &verb, NULL, 1) != B_OK) {
906				dprintf("hda: Setting output selector %" B_PRId32 " failed on "
907					"widget %" B_PRIu32 "!\n", mmvi->values[i].mux,
908					control->nid);
909			}
910			TRACE("set_mix: %" B_PRId32 " selector: %" B_PRIu32 "\n",
911				control->nid, mmvi->values[i].mux);
912		}
913	}
914	return B_OK;
915}
916
917
918static uint32
919default_buffer_length_for_rate(uint32 rate)
920{
921	// keep the latency about the same as 2048 frames per buffer at 44100 Hz
922	switch (rate) {
923	case B_SR_8000:
924		return 512;
925	case B_SR_11025:
926		return 512;
927	case B_SR_16000:
928		return 1024;
929	case B_SR_22050:
930		return 1024;
931	case B_SR_32000:
932		return 2048;
933	case B_SR_44100:
934		return 2048;
935	case B_SR_48000:
936		return 2048;
937	case B_SR_88200:
938		return 4096;
939	case B_SR_96000:
940		return 6144;
941	case B_SR_176400:
942		return 8192;
943	case B_SR_192000:
944		return 10240;
945	case B_SR_384000:
946		return 16384;
947	}
948	return 2048;
949};
950
951
952static status_t
953get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
954{
955	if (requested_settings.play_buffer_frames != 0)
956		data->request_playback_buffer_size = requested_settings.play_buffer_frames;
957
958	if (requested_settings.play_buffer_count != 0)
959		data->request_playback_buffers = requested_settings.play_buffer_count;
960
961	if (requested_settings.record_buffer_frames != 0)
962		data->request_record_buffer_size = requested_settings.record_buffer_frames;
963
964	if (requested_settings.record_buffer_count != 0)
965		data->request_record_buffers = requested_settings.record_buffer_count;
966
967	TRACE("playback: %" B_PRId32 " buffers, %" B_PRId32 " channels, %" B_PRIu32
968		" samples\n", data->request_playback_buffers,
969		data->request_playback_channels, data->request_playback_buffer_size);
970	TRACE("record: %" B_PRId32 " buffers, %" B_PRId32 " channels, %" B_PRIu32
971		" samples\n", data->request_record_buffers,
972		data->request_record_channels, data->request_record_buffer_size);
973
974	/* Determine what buffers we return given the request */
975
976	data->return_playback_buffers = data->request_playback_buffers;
977	data->return_playback_channels = data->request_playback_channels;
978	data->return_playback_buffer_size = data->request_playback_buffer_size;
979	data->return_record_buffers = data->request_record_buffers;
980	data->return_record_channels = data->request_record_channels;
981	data->return_record_buffer_size = data->request_record_buffer_size;
982
983	/* Workaround for Haiku multi_audio API, since it prefers to let the
984	   driver pick values, while the BeOS multi_audio actually gives the
985	   user's defaults. */
986	if (data->return_playback_buffers > STREAM_MAX_BUFFERS
987		|| data->return_playback_buffers < STREAM_MIN_BUFFERS)
988		data->return_playback_buffers = STREAM_MIN_BUFFERS;
989
990	if (data->return_record_buffers > STREAM_MAX_BUFFERS
991		|| data->return_record_buffers < STREAM_MIN_BUFFERS)
992		data->return_record_buffers = STREAM_MIN_BUFFERS;
993
994	if (data->return_playback_buffer_size == 0
995		&& audioGroup->playback_stream != NULL) {
996		data->return_playback_buffer_size = default_buffer_length_for_rate(
997			audioGroup->playback_stream->sample_rate);
998	}
999
1000	if (data->return_record_buffer_size == 0
1001		&& audioGroup->record_stream != NULL) {
1002		data->return_record_buffer_size = default_buffer_length_for_rate(
1003				audioGroup->record_stream->sample_rate);
1004	}
1005
1006	/* ... from here on, we can assume again that a reasonable request is
1007	   being made */
1008
1009	data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD;
1010
1011	/* Copy the settings into the streams */
1012
1013	if (audioGroup->playback_stream != NULL) {
1014		audioGroup->playback_stream->num_buffers = data->return_playback_buffers;
1015		audioGroup->playback_stream->num_channels = data->return_playback_channels;
1016		audioGroup->playback_stream->buffer_length
1017			= data->return_playback_buffer_size;
1018
1019		status_t status = hda_stream_setup_buffers(audioGroup,
1020			audioGroup->playback_stream, "Playback");
1021		if (status != B_OK) {
1022			dprintf("hda: Error setting up playback buffers: %s\n",
1023				strerror(status));
1024			return status;
1025		}
1026	}
1027
1028	if (audioGroup->record_stream != NULL) {
1029		audioGroup->record_stream->num_buffers = data->return_record_buffers;
1030		audioGroup->record_stream->num_channels = data->return_record_channels;
1031		audioGroup->record_stream->buffer_length
1032			= data->return_record_buffer_size;
1033
1034		status_t status = hda_stream_setup_buffers(audioGroup,
1035			audioGroup->record_stream, "Recording");
1036		if (status != B_OK) {
1037			dprintf("hda: Error setting up recording buffers: %s\n",
1038				strerror(status));
1039			return status;
1040		}
1041	}
1042
1043	/* Setup data structure for multi_audio API... */
1044
1045	if (audioGroup->playback_stream != NULL) {
1046		uint32 playbackSampleSize = audioGroup->playback_stream->sample_size;
1047
1048		for (int32 i = 0; i < data->return_playback_buffers; i++) {
1049			struct buffer_desc descs[data->return_playback_channels];
1050			for (int32 channelIndex = 0;
1051					channelIndex < data->return_playback_channels; channelIndex++) {
1052				descs[channelIndex].base = (char*)audioGroup->playback_stream->buffers[i]
1053					+ playbackSampleSize * channelIndex;
1054				descs[channelIndex].stride = playbackSampleSize
1055					* data->return_playback_channels;
1056			}
1057			if (!IS_USER_ADDRESS(data->playback_buffers[i])
1058				|| user_memcpy(data->playback_buffers[i], descs, sizeof(descs))
1059				< B_OK) {
1060				return B_BAD_ADDRESS;
1061			}
1062		}
1063	}
1064
1065	if (audioGroup->record_stream != NULL) {
1066		uint32 recordSampleSize = audioGroup->record_stream->sample_size;
1067
1068		for (int32 i = 0; i < data->return_record_buffers; i++) {
1069			struct buffer_desc descs[data->return_record_channels];
1070			for (int32 channelIndex = 0;
1071					channelIndex < data->return_record_channels; channelIndex++) {
1072				descs[channelIndex].base = (char*)audioGroup->record_stream->buffers[i]
1073					+ recordSampleSize * channelIndex;
1074				descs[channelIndex].stride = recordSampleSize
1075					* data->return_record_channels;
1076			}
1077			if (!IS_USER_ADDRESS(data->record_buffers[i])
1078				|| user_memcpy(data->record_buffers[i], descs, sizeof(descs))
1079				< B_OK) {
1080				return B_BAD_ADDRESS;
1081			}
1082		}
1083	}
1084
1085	return B_OK;
1086}
1087
1088
1089/*! playback_buffer_cycle is the buffer we want to have played */
1090static status_t
1091buffer_exchange(hda_audio_group* audioGroup, multi_buffer_info* data)
1092{
1093	cpu_status status;
1094	status_t err;
1095	multi_buffer_info buffer_info;
1096
1097	if (audioGroup->playback_stream == NULL)
1098		return B_ERROR;
1099
1100	if (!audioGroup->playback_stream->running) {
1101		hda_stream_start(audioGroup->codec->controller,
1102			audioGroup->playback_stream);
1103	}
1104	if (audioGroup->record_stream && !audioGroup->record_stream->running) {
1105		hda_stream_start(audioGroup->codec->controller,
1106			audioGroup->record_stream);
1107	}
1108
1109#ifdef __HAIKU__
1110	if (user_memcpy(&buffer_info, data, sizeof(buffer_info)) < B_OK)
1111		return B_BAD_ADDRESS;
1112#else
1113	memcpy(&buffer_info, data, sizeof(buffer_info));
1114#endif
1115
1116	/* do playback */
1117	err = acquire_sem_etc(audioGroup->codec->controller->buffer_ready_sem,
1118		1, B_CAN_INTERRUPT, 0);
1119	if (err != B_OK) {
1120		ERROR("%s: Error waiting for playback buffer to finish (%s)!\n", __func__,
1121			strerror(err));
1122		return err;
1123	}
1124
1125	status = disable_interrupts();
1126	acquire_spinlock(&audioGroup->playback_stream->lock);
1127
1128	buffer_info.playback_buffer_cycle
1129		= (audioGroup->playback_stream->buffer_cycle)
1130			% audioGroup->playback_stream->num_buffers;
1131	buffer_info.played_real_time = audioGroup->playback_stream->real_time;
1132	buffer_info.played_frames_count = audioGroup->playback_stream->frames_count;
1133
1134	release_spinlock(&audioGroup->playback_stream->lock);
1135
1136	if (audioGroup->record_stream) {
1137		acquire_spinlock(&audioGroup->record_stream->lock);
1138		buffer_info.record_buffer_cycle
1139			= (audioGroup->record_stream->buffer_cycle - 1)
1140				% audioGroup->record_stream->num_buffers;
1141		buffer_info.recorded_real_time = audioGroup->record_stream->real_time;
1142		buffer_info.recorded_frames_count
1143			= audioGroup->record_stream->frames_count;
1144		release_spinlock(&audioGroup->record_stream->lock);
1145	}
1146
1147	restore_interrupts(status);
1148
1149#ifdef __HAIKU__
1150	if (user_memcpy(data, &buffer_info, sizeof(buffer_info)) < B_OK)
1151		return B_BAD_ADDRESS;
1152#else
1153	memcpy(data, &buffer_info, sizeof(buffer_info));
1154#endif
1155
1156#if 0
1157	static int debugBuffersExchanged = 0;
1158
1159	debugBuffersExchanged++;
1160	if ((debugBuffersExchanged % 100) == 1 && debugBuffersExchanged < 1111)
1161		dprintf("%s: %d buffers processed\n", __func__, debugBuffersExchanged);
1162#endif
1163	return B_OK;
1164}
1165
1166
1167static status_t
1168buffer_force_stop(hda_audio_group* audioGroup)
1169{
1170	if (audioGroup->playback_stream != NULL) {
1171		hda_stream_stop(audioGroup->codec->controller,
1172			audioGroup->playback_stream);
1173	}
1174	if (audioGroup->record_stream != NULL) {
1175		hda_stream_stop(audioGroup->codec->controller,
1176			audioGroup->record_stream);
1177	}
1178
1179	return B_OK;
1180}
1181
1182
1183#define cookie_type hda_audio_group
1184#include "../generic/multi.c"
1185
1186
1187status_t
1188multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
1189{
1190	hda_codec* codec = (hda_codec*)cookie;
1191	hda_audio_group* audioGroup;
1192
1193	/* FIXME: We should simply pass the audioGroup into here... */
1194	if (!codec || codec->num_audio_groups == 0)
1195		return ENODEV;
1196
1197	audioGroup = codec->audio_groups[0];
1198
1199	return multi_audio_control_generic(audioGroup, op, arg, len);
1200}
1201