xref: /haiku/src/add-ons/kernel/drivers/audio/hda/hda_multi_audio.cpp (revision 4f2fd49bdc6078128b1391191e4edac647044c3d)
1 /*
2  * Copyright 2007-2008, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ithamar Adema, ithamar AT unet DOT nl
7  *		Axel Dörfler, axeld@pinc-software.de
8  */
9 
10 
11 #include "hmulti_audio.h"
12 #include "driver.h"
13 
14 
15 #ifdef TRACE
16 #	undef TRACE
17 #endif
18 
19 #define TRACE_MULTI_AUDIO
20 #ifdef TRACE_MULTI_AUDIO
21 #	define TRACE(a...) dprintf("\33[34mhda:\33[0m " a)
22 #else
23 #	define TRACE(a...) ;
24 #endif
25 
26 typedef enum {
27 	B_MIX_GAIN = 1 << 0,
28 	B_MIX_MUTE = 1 << 1
29 } mixer_type;
30 
31 
32 static multi_channel_info sChannels[] = {
33 	{  0, B_MULTI_OUTPUT_CHANNEL,	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
34 	{  1, B_MULTI_OUTPUT_CHANNEL,	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
35 	{  2, B_MULTI_INPUT_CHANNEL,	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
36 	{  3, B_MULTI_INPUT_CHANNEL,	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
37 	{  4, B_MULTI_OUTPUT_BUS,		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS,
38 			B_CHANNEL_MINI_JACK_STEREO },
39 	{  5, B_MULTI_OUTPUT_BUS,		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS,
40 			B_CHANNEL_MINI_JACK_STEREO },
41 	{  6, B_MULTI_INPUT_BUS,		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS,
42 			B_CHANNEL_MINI_JACK_STEREO },
43 	{  7, B_MULTI_INPUT_BUS,		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS,
44 			B_CHANNEL_MINI_JACK_STEREO },
45 };
46 
47 
48 static int32
49 format2size(uint32 format)
50 {
51 	switch (format) {
52 		case B_FMT_8BIT_S:
53 		case B_FMT_16BIT:
54 			return 2;
55 
56 		case B_FMT_18BIT:
57 		case B_FMT_20BIT:
58 		case B_FMT_24BIT:
59 		case B_FMT_32BIT:
60 		case B_FMT_FLOAT:
61 			return 4;
62 
63 		default:
64 			return -1;
65 	}
66 }
67 
68 
69 static status_t
70 get_description(hda_audio_group* audioGroup, multi_description* data)
71 {
72 	data->interface_version = B_CURRENT_INTERFACE_VERSION;
73 	data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
74 
75 	strcpy(data->friendly_name, "HD Audio");
76 	strcpy(data->vendor_info, "Haiku");
77 
78 	int32 inChannels = 0;
79 	if (audioGroup->record_stream != NULL)
80 		inChannels = 2;
81 
82 	int32 outChannels = 0;
83 	if (audioGroup->playback_stream != NULL)
84 		outChannels = 2;
85 
86 	data->output_channel_count = outChannels;
87 	data->output_bus_channel_count = outChannels;
88 	data->input_channel_count = inChannels;
89 	data->input_bus_channel_count = inChannels;
90 	data->aux_bus_channel_count = 0;
91 
92 	dprintf("%s: request_channel_count: %ld\n", __func__,
93 		data->request_channel_count);
94 
95 	if (data->request_channel_count >= (int)(sizeof(sChannels)
96 			/ sizeof(sChannels[0]))) {
97 		memcpy(data->channels, &sChannels, sizeof(sChannels));
98 	}
99 
100 	/* determine output/input rates */
101 	data->output_rates = audioGroup->widget.d.io.rates;
102 	data->input_rates = audioGroup->widget.d.io.rates;
103 
104 	/* force existance of 48kHz if variable rates are not supported */
105 	if (data->output_rates == 0)
106 		data->output_rates = B_SR_48000;
107 	if (data->input_rates == 0)
108 		data->input_rates = B_SR_48000;
109 
110 	data->max_cvsr_rate = 0;
111 	data->min_cvsr_rate = 0;
112 
113 	data->output_formats = audioGroup->widget.d.io.formats;
114 	data->input_formats = audioGroup->widget.d.io.formats;
115 	data->lock_sources = B_MULTI_LOCK_INTERNAL;
116 	data->timecode_sources = 0;
117 	data->interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
118 	data->start_latency = 30000;
119 
120 	strcpy(data->control_panel, "");
121 
122 	return B_OK;
123 }
124 
125 
126 static status_t
127 get_enabled_channels(hda_audio_group* audioGroup, multi_channel_enable* data)
128 {
129 	B_SET_CHANNEL(data->enable_bits, 0, true);
130 	B_SET_CHANNEL(data->enable_bits, 1, true);
131 	B_SET_CHANNEL(data->enable_bits, 2, true);
132 	B_SET_CHANNEL(data->enable_bits, 3, true);
133 	data->lock_source = B_MULTI_LOCK_INTERNAL;
134 
135 	return B_OK;
136 }
137 
138 
139 static status_t
140 get_global_format(hda_audio_group* audioGroup, multi_format_info* data)
141 {
142 	data->output_latency = 0;
143 	data->input_latency = 0;
144 	data->timecode_kind = 0;
145 
146 	if (audioGroup->playback_stream != NULL) {
147 		data->output.format = audioGroup->playback_stream->sample_format;
148 		data->output.rate = audioGroup->playback_stream->sample_rate;
149 	} else {
150 		data->output.format = 0;
151 		data->output.rate = 0;
152 	}
153 
154 	if (audioGroup->record_stream != NULL) {
155 		data->input.format = audioGroup->record_stream->sample_format;
156 		data->input.rate = audioGroup->record_stream->sample_format;
157 	} else {
158 		data->input.format = 0;
159 		data->input.rate = 0;
160 	}
161 
162 	return B_OK;
163 }
164 
165 
166 static status_t
167 set_global_format(hda_audio_group* audioGroup, multi_format_info* data)
168 {
169 	// TODO: it looks like we're not supposed to fail; fix this!
170 #if 0
171 	if ((data->output.format & audioGroup->supported_formats) == 0)
172 		|| (data->output.rate & audioGroup->supported_rates) == 0)
173 		return B_BAD_VALUE;
174 #endif
175 
176 	if (audioGroup->playback_stream != NULL) {
177 		audioGroup->playback_stream->sample_format = data->output.format;
178 		audioGroup->playback_stream->sample_rate = data->output.rate;
179 		audioGroup->playback_stream->sample_size = format2size(
180 			audioGroup->playback_stream->sample_format);
181 	}
182 
183 	if (audioGroup->record_stream != NULL) {
184 		audioGroup->record_stream->sample_rate = data->input.rate;
185 		audioGroup->record_stream->sample_format = data->input.format;
186 		audioGroup->record_stream->sample_size = format2size(
187 			audioGroup->record_stream->sample_format);
188 	}
189 
190 	return B_OK;
191 }
192 
193 
194 static int32
195 hda_create_group_control(hda_multi *multi, uint32 *index, int32 parent,
196 	enum strind_id string, const char* name) {
197 	uint32 i = *index;
198 	(*index)++;
199 	multi->controls[i].mix_control.id = MULTI_CONTROL_FIRSTID + i;
200 	multi->controls[i].mix_control.parent = parent;
201 	multi->controls[i].mix_control.flags = B_MULTI_MIX_GROUP;
202 	multi->controls[i].mix_control.master = MULTI_CONTROL_MASTERID;
203 	multi->controls[i].mix_control.string = string;
204 	if (name)
205 		strcpy(multi->controls[i].mix_control.name, name);
206 
207 	return multi->controls[i].mix_control.id;
208 }
209 
210 
211 static void
212 hda_create_channel_control(hda_multi *multi, uint32 *index, int32 parent, int32 string,
213 	hda_widget& widget, bool input, uint32 capabilities, int32 inputIndex, bool &gain, bool& mute) {
214 	uint32 i = *index, id;
215 	hda_multi_mixer_control control;
216 
217 	control.nid = widget.node_id;
218 	control.input = input;
219 	control.mute = 0;
220 	control.gain = 0;
221 	control.capabilities = capabilities;
222 	control.index = inputIndex;
223 	control.mix_control.master = MULTI_CONTROL_MASTERID;
224 	control.mix_control.parent = parent;
225 
226 	if (mute && capabilities & AMP_CAP_MUTE) {
227 		control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
228 		control.mix_control.flags = B_MULTI_MIX_ENABLE;
229 		control.mix_control.string = S_MUTE;
230 		control.type = B_MIX_MUTE;
231 		multi->controls[i++] = control;
232 		TRACE("control nid %ld mute\n", control.nid);
233 		mute = false;
234 	}
235 
236 	if (gain && AMP_CAP_NUM_STEPS(capabilities) >= 1) {
237 		control.mix_control.gain.granularity = AMP_CAP_STEP_SIZE(capabilities);
238 		control.mix_control.gain.min_gain = (0.0 - AMP_CAP_OFFSET(capabilities))
239 			* control.mix_control.gain.granularity;
240 		control.mix_control.gain.max_gain = (AMP_CAP_NUM_STEPS(capabilities) - AMP_CAP_OFFSET(capabilities))
241 			* control.mix_control.gain.granularity;
242 
243 		control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
244 		control.mix_control.flags = B_MULTI_MIX_GAIN;
245 		control.mix_control.string = S_null;
246 		control.type = B_MIX_GAIN;
247 		strcpy(control.mix_control.name, "Gain");
248 		multi->controls[i++] = control;
249 		id = control.mix_control.id;
250 
251 		// second channel
252 		control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
253 		control.mix_control.master = id;
254 		multi->controls[i++] = control;
255 		TRACE("control nid %ld %f min %f max %f\n", control.nid, control.mix_control.gain.granularity,
256 			control.mix_control.gain.min_gain, control.mix_control.gain.max_gain);
257 		gain = false;
258 	}
259 
260 	*index = i;
261 }
262 
263 
264 static enum strind_id
265 hda_find_multi_string(hda_widget& widget)
266 {
267 	switch (CONF_DEFAULT_DEVICE(widget.d.pin.config)) {
268 		case PIN_DEV_CD:
269 			return S_CD;
270 		case PIN_DEV_LINE_IN:
271 		case PIN_DEV_LINE_OUT:
272 			return S_LINE;
273 		case PIN_DEV_MIC_IN:
274 			return S_MIC;
275 		case PIN_DEV_AUX:
276 			return S_AUX;
277 		case PIN_DEV_SPDIF_IN:
278 		case PIN_DEV_SPDIF_OUT:
279 			return S_SPDIF;
280 		case PIN_DEV_HEAD_PHONE_OUT:
281 			return S_HEADPHONE;
282 	}
283 	TRACE("couln't find a string for widget %ld in hda_find_multi_string()\n", widget.node_id);
284 	return S_null;
285 }
286 
287 static const char *
288 hda_find_multi_custom_string(hda_widget& widget)
289 {
290 	switch (CONF_DEFAULT_DEVICE(widget.d.pin.config)) {
291 		case PIN_DEV_LINE_IN:
292 		case PIN_DEV_LINE_OUT:
293 		case PIN_DEV_MIC_IN:
294 			switch (CONF_DEFAULT_COLOR(widget.d.pin.config)) {
295 				case 1:
296 					return "Rear";
297 				case 2:
298 					return "Side";
299 				case 3:
300 					return "Line In";
301 				case 4:
302 					return "Front";
303 				case 6:
304 					return "Center/Sub";
305 				case 9:
306 					return "Mic in";
307 			}
308 			if (CONF_DEFAULT_DEVICE(widget.d.pin.config) == PIN_DEV_LINE_IN)
309 				return "Line In";
310 			if (CONF_DEFAULT_DEVICE(widget.d.pin.config) == PIN_DEV_MIC_IN)
311 				return "Mic In";
312 			return "Line Out";
313 			break;
314 		case PIN_DEV_SPDIF_IN:
315 			return "SPDIF In";
316 		case PIN_DEV_SPDIF_OUT:
317 			return "SPDIF Out";
318 		case PIN_DEV_CD:
319 			return "CD";
320 		case PIN_DEV_HEAD_PHONE_OUT:
321 			return "Headphones";
322 		case PIN_DEV_SPEAKER:
323 			return "Speaker";
324 	}
325 	TRACE("couldn't find a string for widget %ld in hda_find_multi_custom_string()\n", widget.node_id);
326 	return NULL;
327 }
328 
329 
330 static void
331 hda_create_control_for_complex(hda_multi *multi, uint32 *index, uint32 parent,
332 	hda_widget& widget, bool& gain, bool& mute)
333 {
334 	hda_audio_group *audioGroup = multi->group;
335 
336 	switch (widget.type) {
337 		case WT_AUDIO_OUTPUT:
338 		case WT_AUDIO_MIXER:
339 		case WT_AUDIO_SELECTOR:
340 		case WT_PIN_COMPLEX:
341 			break;
342 		default:
343 			return;
344 	}
345 
346 	if (widget.flags & WIDGET_FLAG_WIDGET_PATH)
347 		return;
348 
349 	TRACE("  create widget nid %lu\n", widget.node_id);
350 	hda_create_channel_control(multi, index, parent, 0,
351 		widget, false, widget.capabilities.output_amplifier, 0, gain, mute);
352 
353 	if (!gain && !mute) {
354 		widget.flags |= WIDGET_FLAG_WIDGET_PATH;
355 		return;
356 	}
357 
358 	if (widget.type & WT_AUDIO_MIXER) {
359 		hda_create_channel_control(multi, index, parent, 0,
360 			widget, true, widget.capabilities.input_amplifier, 0, gain, mute);
361 		if (!gain && !mute) {
362 			widget.flags |= WIDGET_FLAG_WIDGET_PATH;
363 			return;
364 		}
365 	}
366 
367 	if ((widget.type & WT_AUDIO_OUTPUT) == 0
368 		&& widget.num_inputs > 0) {
369 		hda_widget &child = * hda_audio_group_get_widget(audioGroup, widget.inputs[widget.active_input]);
370 		hda_create_control_for_complex(multi, index, parent, child, gain, mute);
371 	}
372 
373 	widget.flags |= WIDGET_FLAG_WIDGET_PATH;
374 }
375 
376 
377 static status_t
378 hda_create_controls_list(hda_multi *multi)
379 {
380 	uint32 index = 0, parent, parent2;
381 	hda_audio_group *audioGroup = multi->group;
382 
383 	parent = hda_create_group_control(multi, &index, 0, S_OUTPUT, NULL);
384 
385 	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
386 		hda_widget& complex = audioGroup->widgets[i];
387 
388 		if (complex.type != WT_PIN_COMPLEX)
389 			continue;
390 		if (!PIN_CAP_IS_OUTPUT(complex.d.pin.capabilities))
391 			continue;
392 		if ((complex.flags & WIDGET_FLAG_OUTPUT_PATH) == 0)
393 			continue;
394 
395 		TRACE("create complex nid %lu\n", complex.node_id);
396 
397 		parent2 = hda_create_group_control(multi, &index,
398 			parent, S_null, hda_find_multi_custom_string(complex));
399 		bool gain = true, mute = true;
400 
401 		hda_create_control_for_complex(multi, &index, parent2, complex, gain, mute);
402 	}
403 
404 	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
405 		hda_widget& widget = audioGroup->widgets[i];
406 
407 		if (widget.type != WT_AUDIO_MIXER)
408 			continue;
409 		if (widget.flags & WIDGET_FLAG_WIDGET_PATH)
410 			continue;
411 
412 		TRACE("create widget nid %lu\n", widget.node_id);
413 
414 		if (AMP_CAP_NUM_STEPS(widget.capabilities.input_amplifier) >= 1) {
415 
416 			for (uint32 j = 0; j < widget.num_inputs; j++) {
417 				hda_widget *complex = hda_audio_group_get_widget(audioGroup, widget.inputs[j]);
418 				if (complex->type != WT_PIN_COMPLEX)
419 					continue;
420 				if (!PIN_CAP_IS_INPUT(complex->d.pin.capabilities))
421 					continue;
422 				if (complex->flags & WIDGET_FLAG_OUTPUT_PATH)
423 					continue;
424 				TRACE("  create widget input nid %lu\n", widget.inputs[j]);
425 				parent2 = hda_create_group_control(multi, &index,
426 					parent, S_null, hda_find_multi_custom_string(*complex));
427 				bool gain = true, mute = true;
428 				hda_create_channel_control(multi, &index, parent2, 0,
429 					widget, true, widget.capabilities.input_amplifier, j, gain, mute);
430 			}
431 		}
432 
433 		widget.flags |= WIDGET_FLAG_WIDGET_PATH;
434 	}
435 
436 	parent = hda_create_group_control(multi, &index, 0, S_INPUT, NULL);
437 
438 	for (uint32 i = 0; i < audioGroup->widget_count; i++) {
439 		hda_widget& widget = audioGroup->widgets[i];
440 
441 		if (widget.type != WT_AUDIO_INPUT)
442 			continue;
443 
444 		uint32 capabilities = widget.capabilities.input_amplifier;
445 		if (AMP_CAP_NUM_STEPS(capabilities) < 1)
446 			continue;
447 
448 		parent2 = hda_create_group_control(multi, &index,
449 			parent, hda_find_multi_string(widget), "Input");
450 		bool gain = true, mute = true;
451 		hda_create_channel_control(multi, &index, parent2, 0,
452 			widget, true, capabilities, 0, gain, mute);
453 	}
454 
455 	multi->control_count = index;
456 	TRACE("multi->control_count %lu\n", multi->control_count);
457 	return B_OK;
458 }
459 
460 
461 static status_t
462 list_mix_controls(hda_audio_group* audioGroup, multi_mix_control_info* MMCI)
463 {
464 	multi_mix_control	*MMC;
465 	uint32 i;
466 
467 	MMC = MMCI->controls;
468 	if (MMCI->control_count < 24)
469 		return B_ERROR;
470 
471 	if (hda_create_controls_list(audioGroup->multi) < B_OK)
472 		return B_ERROR;
473 	for (i=0; i<audioGroup->multi->control_count; i++) {
474 		MMC[i] = audioGroup->multi->controls[i].mix_control;
475 	}
476 
477 	MMCI->control_count = audioGroup->multi->control_count;
478 	return B_OK;
479 }
480 
481 
482 static status_t
483 list_mix_connections(hda_audio_group* audioGroup,
484 	multi_mix_connection_info* data)
485 {
486 	data->actual_count = 0;
487 	return B_OK;
488 }
489 
490 
491 static status_t
492 list_mix_channels(hda_audio_group* audioGroup, multi_mix_channel_info *data)
493 {
494 	return B_OK;
495 }
496 
497 
498 static void
499 get_control_gain_mute(hda_audio_group* audioGroup, hda_multi_mixer_control *control, uint32 *resp)
500 {
501 	uint32 verb[2];
502 	verb[0] = MAKE_VERB(audioGroup->codec->addr,
503 		control->nid,
504 		VID_GET_AMPLIFIER_GAIN_MUTE,
505 		(control->input ? AMP_GET_INPUT : AMP_GET_OUTPUT)
506 		| AMP_GET_LEFT_CHANNEL | AMP_GET_INPUT_INDEX(control->index));
507 	verb[1] = MAKE_VERB(audioGroup->codec->addr,
508 		control->nid,
509 		VID_GET_AMPLIFIER_GAIN_MUTE,
510 		(control->input ? AMP_GET_INPUT : AMP_GET_OUTPUT)
511 		| AMP_GET_RIGHT_CHANNEL | AMP_GET_INPUT_INDEX(control->index));
512 	hda_send_verbs(audioGroup->codec, verb, resp, 2);
513 }
514 
515 
516 static status_t
517 get_mix(hda_audio_group* audioGroup, multi_mix_value_info * MMVI)
518 {
519 	int32 i;
520 	uint32 id;
521 	hda_multi_mixer_control *control = NULL;
522 	for (i=0; i < MMVI->item_count; i++) {
523 		id = MMVI->values[i].id - MULTI_CONTROL_FIRSTID;
524 		if (id < 0 || id >= audioGroup->multi->control_count) {
525 			dprintf("hda: get_mix : invalid control id requested : %li\n", id);
526 			continue;
527 		}
528 		control = &audioGroup->multi->controls[id];
529 
530 		if (control->mix_control.flags & (B_MULTI_MIX_GAIN | B_MULTI_MIX_ENABLE)) {
531 			uint32 resp[2];
532 			get_control_gain_mute(audioGroup, control, resp);
533 			if (control->mix_control.flags & B_MULTI_MIX_ENABLE) {
534 				MMVI->values[i].enable = (resp[0] & AMP_MUTE) != 0;
535 				TRACE("get_mix: %ld mute: %d\n", control->nid, MMVI->values[i].enable);
536 			} else if (control->mix_control.flags & B_MULTI_MIX_GAIN) {
537 				uint32 value;
538 				if (control->mix_control.master == MULTI_CONTROL_MASTERID)
539 					value = resp[0] & AMP_GAIN_MASK;
540 				else
541 					value = resp[1] & AMP_GAIN_MASK;
542 				MMVI->values[i].gain = (value - AMP_CAP_OFFSET(control->capabilities))
543 						* AMP_CAP_STEP_SIZE(control->capabilities);
544 				TRACE("get_mix: %ld gain: %f (%ld)\n", control->nid, MMVI->values[i].gain, value);
545 			}
546 
547 
548 		}
549 
550 		/*if (control->mix_control.flags & B_MULTI_MIX_MUX && control->get) {
551 			float values[1];
552 			control->get(audioGroup, control, values);
553 			MMVI->values[i].mux = (int32)values[0];
554 		}*/
555 	}
556 	return B_OK;
557 }
558 
559 
560 static status_t
561 set_mix(hda_audio_group* audioGroup, multi_mix_value_info * MMVI)
562 {
563 	int32 i;
564 	uint32 id;
565 	hda_multi_mixer_control *control = NULL;
566 	for (i=0; i < MMVI->item_count; i++) {
567 		id = MMVI->values[i].id - MULTI_CONTROL_FIRSTID;
568 		if (id < 0 || id >= audioGroup->multi->control_count) {
569 			dprintf("set_mix : invalid control id requested : %li\n", id);
570 			continue;
571 		}
572 		control = &audioGroup->multi->controls[id];
573 
574 		if (control->mix_control.flags & B_MULTI_MIX_ENABLE) {
575 			control->mute = (MMVI->values[i].enable ? AMP_MUTE : 0);
576 			TRACE("set_mix: %ld mute: %lx\n", control->nid, control->mute);
577 			uint32 resp[2];
578 			get_control_gain_mute(audioGroup, control, resp);
579 
580 			uint32 verb[2];
581 			verb[0] = MAKE_VERB(audioGroup->codec->addr,
582 				control->nid,
583 				VID_SET_AMPLIFIER_GAIN_MUTE,
584 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
585 				| AMP_SET_LEFT_CHANNEL
586 				| AMP_SET_INPUT_INDEX(control->index)
587 				| control->mute
588 				| resp[0] & AMP_GAIN_MASK);
589 			TRACE("set_mix: sending verb to %ld: %lx %lx %x %lx\n", control->nid,
590 				control->mute, resp[0] & AMP_GAIN_MASK, control->input,
591 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
592 				| AMP_SET_LEFT_CHANNEL
593 				| AMP_SET_INPUT_INDEX(control->index)
594 				| control->mute
595 				| resp[0] & AMP_GAIN_MASK);
596 			verb[1] = MAKE_VERB(audioGroup->codec->addr,
597 				control->nid,
598 				VID_SET_AMPLIFIER_GAIN_MUTE,
599 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
600 				| AMP_SET_RIGHT_CHANNEL
601 				| AMP_SET_INPUT_INDEX(control->index)
602 				| control->mute
603 				| resp[1] & AMP_GAIN_MASK);
604 			TRACE("set_mix: ctrl2 sending verb to %ld: %lx %lx %x\n", control->nid,
605 				control->mute, resp[1] & AMP_GAIN_MASK, control->input);
606 			hda_send_verbs(audioGroup->codec, verb, NULL, 2);
607 		} else if (control->mix_control.flags & B_MULTI_MIX_GAIN) {
608 			hda_multi_mixer_control *control2 = NULL;
609 			if (i+1<MMVI->item_count) {
610 				id = MMVI->values[i + 1].id - MULTI_CONTROL_FIRSTID;
611 				if (id < 0 || id >= audioGroup->multi->control_count) {
612 					dprintf("set_mix : invalid control id requested : %li\n", id);
613 				} else {
614 					control2 = &audioGroup->multi->controls[id];
615 					if (control2->mix_control.master != control->mix_control.id)
616 						control2 = NULL;
617 				}
618 			}
619 
620 			if (control->mix_control.master == MULTI_CONTROL_MASTERID)
621 				control->gain = (uint32)(MMVI->values[i].gain / AMP_CAP_STEP_SIZE(control->capabilities)
622 				+ AMP_CAP_OFFSET(control->capabilities));
623 
624 			if (control2 && control2->mix_control.master != MULTI_CONTROL_MASTERID)
625 				control2->gain = (uint32)(MMVI->values[i+1].gain / AMP_CAP_STEP_SIZE(control2->capabilities)
626 					+ AMP_CAP_OFFSET(control2->capabilities));
627 			TRACE("set_mix: %ld gain: %lx and %ld gain: %lx\n",
628 				control->nid, control->gain, control2->nid, control2->gain);
629 			uint32 resp[2];
630 			get_control_gain_mute(audioGroup, control, resp);
631 			control->mute = resp[0] & AMP_MUTE;
632 			if (control2)
633 				control2->mute = resp[1] & AMP_MUTE;
634 
635 			uint32 verb[2];
636 			verb[0] = MAKE_VERB(audioGroup->codec->addr,
637 				control->nid,
638 				VID_SET_AMPLIFIER_GAIN_MUTE,
639 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
640 				| AMP_SET_LEFT_CHANNEL
641 				| AMP_SET_INPUT_INDEX(control->index)
642 				| (control->mute & AMP_MUTE)
643 				| (control->gain & AMP_GAIN_MASK));
644 			TRACE("set_mix: sending verb to %ld: %lx %lx %x %lx\n", control->nid,
645 				control->mute, control->gain, control->input,
646 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
647 				| AMP_SET_LEFT_CHANNEL
648 				| AMP_SET_INPUT_INDEX(control->index)
649 				| (control->mute & AMP_MUTE)
650 				| (control->gain & AMP_GAIN_MASK));
651 			if (control2) {
652 				verb[1] = MAKE_VERB(audioGroup->codec->addr,
653 					control2->nid,
654 					VID_SET_AMPLIFIER_GAIN_MUTE,
655 					(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
656 					| AMP_SET_RIGHT_CHANNEL
657 					| AMP_SET_INPUT_INDEX(control->index)
658 					| (control2->mute & AMP_MUTE)
659 					| (control2->gain & AMP_GAIN_MASK));
660 				TRACE("set_mix: ctrl2 sending verb to %ld: %lx %lx %x\n", control2->nid,
661 					control2->mute, control2->gain, control2->input);
662 			}
663 			hda_send_verbs(audioGroup->codec, verb, NULL, control2 ? 2 : 1);
664 
665 			if (control2)
666 			i++;
667 		}
668 
669 		/*if (control->mix_control.flags & B_MULTI_MIX_MUX && control->set) {
670 			float values[1];
671 
672 			values[0] = (float)MMVI->values[i].mux;
673 			control->set(card, control->channel, control->type, values);
674 		}*/
675 	}
676 	return B_OK;
677 }
678 
679 
680 static status_t
681 get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
682 {
683 	TRACE("playback: %ld buffers, %ld channels, %ld samples\n",
684 		data->request_playback_buffers, data->request_playback_channels,
685 		data->request_playback_buffer_size);
686 	TRACE("record: %ld buffers, %ld channels, %ld samples\n",
687 		data->request_record_buffers, data->request_record_channels,
688 		data->request_record_buffer_size);
689 
690 	/* Determine what buffers we return given the request */
691 
692 	data->return_playback_buffers = data->request_playback_buffers;
693 	data->return_playback_channels = data->request_playback_channels;
694 	data->return_playback_buffer_size = data->request_playback_buffer_size;
695 	data->return_record_buffers = data->request_record_buffers;
696 	data->return_record_channels = data->request_record_channels;
697 	data->return_record_buffer_size = data->request_record_buffer_size;
698 
699 	/* Workaround for Haiku multi_audio API, since it prefers to let the
700 	   driver pick values, while the BeOS multi_audio actually gives the
701 	   user's defaults. */
702 	if (data->return_playback_buffers > STREAM_MAX_BUFFERS
703 		|| data->return_playback_buffers < STREAM_MIN_BUFFERS)
704 		data->return_playback_buffers = STREAM_MIN_BUFFERS;
705 
706 	if (data->return_record_buffers > STREAM_MAX_BUFFERS
707 		|| data->return_record_buffers < STREAM_MIN_BUFFERS)
708 		data->return_record_buffers = STREAM_MIN_BUFFERS;
709 
710 	if (data->return_playback_buffer_size == 0)
711 		data->return_playback_buffer_size = DEFAULT_FRAMES_PER_BUFFER;
712 
713 	if (data->return_record_buffer_size == 0)
714 		data->return_record_buffer_size = DEFAULT_FRAMES_PER_BUFFER;
715 
716 	/* ... from here on, we can assume again that a reasonable request is
717 	   being made */
718 
719 	data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD;
720 
721 	/* Copy the settings into the streams */
722 
723 	if (audioGroup->playback_stream != NULL) {
724 		audioGroup->playback_stream->num_buffers = data->return_playback_buffers;
725 		audioGroup->playback_stream->num_channels = data->return_playback_channels;
726 		audioGroup->playback_stream->buffer_length
727 			= data->return_playback_buffer_size;
728 
729 		status_t status = hda_stream_setup_buffers(audioGroup,
730 			audioGroup->playback_stream, "Playback");
731 		if (status != B_OK) {
732 			dprintf("hda: Error setting up playback buffers: %s\n",
733 				strerror(status));
734 			return status;
735 		}
736 	}
737 
738 	if (audioGroup->record_stream != NULL) {
739 		audioGroup->record_stream->num_buffers = data->return_record_buffers;
740 		audioGroup->record_stream->num_channels = data->return_record_channels;
741 		audioGroup->record_stream->buffer_length
742 			= data->return_record_buffer_size;
743 
744 		status_t status = hda_stream_setup_buffers(audioGroup,
745 			audioGroup->record_stream, "Recording");
746 		if (status != B_OK) {
747 			dprintf("hda: Error setting up recording buffers: %s\n",
748 				strerror(status));
749 			return status;
750 		}
751 	}
752 
753 	/* Setup data structure for multi_audio API... */
754 
755 	if (audioGroup->playback_stream != NULL) {
756 		uint32 playbackSampleSize = audioGroup->playback_stream->sample_size;
757 
758 		for (int32 i = 0; i < data->return_playback_buffers; i++) {
759 			for (int32 channelIndex = 0;
760 					channelIndex < data->return_playback_channels; channelIndex++) {
761 				data->playback_buffers[i][channelIndex].base
762 					= (char*)audioGroup->playback_stream->buffers[i]
763 						+ playbackSampleSize * channelIndex;
764 				data->playback_buffers[i][channelIndex].stride
765 					= playbackSampleSize * data->return_playback_channels;
766 			}
767 		}
768 	}
769 
770 	if (audioGroup->record_stream != NULL) {
771 		uint32 recordSampleSize = audioGroup->record_stream->sample_size;
772 
773 		for (int32 i = 0; i < data->return_record_buffers; i++) {
774 			for (int32 channelIndex = 0;
775 					channelIndex < data->return_record_channels; channelIndex++) {
776 				data->record_buffers[i][channelIndex].base
777 					= (char*)audioGroup->record_stream->buffers[i]
778 						+ recordSampleSize * channelIndex;
779 				data->record_buffers[i][channelIndex].stride
780 					= recordSampleSize * data->return_record_channels;
781 			}
782 		}
783 	}
784 
785 	return B_OK;
786 }
787 
788 
789 /*! playback_buffer_cycle is the buffer we want to have played */
790 static status_t
791 buffer_exchange(hda_audio_group* audioGroup, multi_buffer_info* data)
792 {
793 	static int debug_buffers_exchanged = 0;
794 	cpu_status status;
795 	status_t err;
796 	multi_buffer_info buffer_info;
797 
798 	if (audioGroup->playback_stream == NULL)
799 		return B_ERROR;
800 
801 	if (!audioGroup->playback_stream->running) {
802 		hda_stream_start(audioGroup->codec->controller,
803 			audioGroup->playback_stream);
804 	}
805 	if (audioGroup->record_stream && !audioGroup->record_stream->running) {
806 		hda_stream_start(audioGroup->codec->controller,
807 			audioGroup->record_stream);
808 	}
809 
810 #ifdef __HAIKU__
811 	if (user_memcpy(&buffer_info, data, sizeof(buffer_info)) < B_OK)
812 		return B_BAD_ADDRESS;
813 #else
814 	memcpy(&buffer_info, data, sizeof(buffer_info));
815 #endif
816 
817 	/* do playback */
818 	err = acquire_sem_etc(audioGroup->playback_stream->buffer_ready_sem,
819 		1, B_CAN_INTERRUPT, 0);
820 	if (err != B_OK) {
821 		dprintf("%s: Error waiting for playback buffer to finish (%s)!\n", __func__,
822 			strerror(err));
823 		return err;
824 	}
825 
826 	status = disable_interrupts();
827 	acquire_spinlock(&audioGroup->playback_stream->lock);
828 
829 	buffer_info.playback_buffer_cycle = audioGroup->playback_stream->buffer_cycle;
830 	buffer_info.played_real_time = audioGroup->playback_stream->real_time;
831 	buffer_info.played_frames_count = audioGroup->playback_stream->frames_count;
832 
833 	release_spinlock(&audioGroup->playback_stream->lock);
834 
835 	if (audioGroup->record_stream) {
836 		acquire_spinlock(&audioGroup->record_stream->lock);
837 		buffer_info.record_buffer_cycle = audioGroup->record_stream->buffer_cycle;
838 		buffer_info.recorded_real_time = audioGroup->record_stream->real_time;
839 		buffer_info.recorded_frames_count = audioGroup->record_stream->frames_count;
840 		release_spinlock(&audioGroup->record_stream->lock);
841 	}
842 
843 	restore_interrupts(status);
844 
845 #ifdef __HAIKU__
846 	if (user_memcpy(data, &buffer_info, sizeof(buffer_info)) < B_OK)
847 		return B_BAD_ADDRESS;
848 #else
849 	memcpy(data, &buffer_info, sizeof(buffer_info));
850 #endif
851 
852 	debug_buffers_exchanged++;
853 	if (((debug_buffers_exchanged % 100) == 1) && (debug_buffers_exchanged < 1111)) {
854 		dprintf("%s: %d buffers processed\n", __func__, debug_buffers_exchanged);
855 	}
856 
857 	return B_OK;
858 }
859 
860 
861 static status_t
862 buffer_force_stop(hda_audio_group* audioGroup)
863 {
864 	if (audioGroup->playback_stream != NULL) {
865 		hda_stream_stop(audioGroup->codec->controller,
866 			audioGroup->playback_stream);
867 	}
868 	if (audioGroup->record_stream != NULL) {
869 		hda_stream_stop(audioGroup->codec->controller,
870 			audioGroup->record_stream);
871 	}
872 	//hda_stream_stop(audioGroup->codec->controller, audioGroup->record_stream);
873 
874 	return B_OK;
875 }
876 
877 
878 status_t
879 multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
880 {
881 	hda_codec* codec = (hda_codec*)cookie;
882 	hda_audio_group* audioGroup;
883 
884 	/* FIXME: We should simply pass the audioGroup into here... */
885 	if (!codec || codec->num_audio_groups == 0)
886 		return ENODEV;
887 
888 	audioGroup = codec->audio_groups[0];
889 
890 	// TODO: make userland-safe when built for Haiku!
891 
892 	switch (op) {
893 		case B_MULTI_GET_DESCRIPTION:
894 		{
895 #ifdef __HAIKU__
896 			multi_description description;
897 			multi_channel_info channels[16];
898 			multi_channel_info* originalChannels;
899 
900 			if (user_memcpy(&description, arg, sizeof(multi_description))
901 					!= B_OK)
902 				return B_BAD_ADDRESS;
903 
904 			originalChannels = description.channels;
905 			description.channels = channels;
906 			if (description.request_channel_count > 16)
907 				description.request_channel_count = 16;
908 
909 			status_t status = get_description(audioGroup, &description);
910 			if (status != B_OK)
911 				return status;
912 
913 			description.channels = originalChannels;
914 			if (user_memcpy(arg, &description, sizeof(multi_description))
915 					!= B_OK)
916 				return B_BAD_ADDRESS;
917 			return user_memcpy(originalChannels, channels, sizeof(multi_channel_info)
918 					* description.request_channel_count);
919 #else
920 			return get_description(audioGroup, (multi_description*)arg);
921 #endif
922 		}
923 
924 		case B_MULTI_GET_ENABLED_CHANNELS:
925 			return get_enabled_channels(audioGroup, (multi_channel_enable*)arg);
926 		case B_MULTI_SET_ENABLED_CHANNELS:
927 			return B_OK;
928 
929 		case B_MULTI_GET_GLOBAL_FORMAT:
930 			return get_global_format(audioGroup, (multi_format_info*)arg);
931 		case B_MULTI_SET_GLOBAL_FORMAT:
932 			return set_global_format(audioGroup, (multi_format_info*)arg);
933 
934 		case B_MULTI_LIST_MIX_CHANNELS:
935 			return list_mix_channels(audioGroup, (multi_mix_channel_info*)arg);
936 		case B_MULTI_LIST_MIX_CONTROLS:
937 			return list_mix_controls(audioGroup, (multi_mix_control_info*)arg);
938 		case B_MULTI_LIST_MIX_CONNECTIONS:
939 			return list_mix_connections(audioGroup,
940 				(multi_mix_connection_info*)arg);
941 		case B_MULTI_GET_MIX:
942 			return get_mix(audioGroup, (multi_mix_value_info *)arg);
943 		case B_MULTI_SET_MIX:
944 			return set_mix(audioGroup, (multi_mix_value_info *)arg);
945 
946 		case B_MULTI_GET_BUFFERS:
947 			return get_buffers(audioGroup, (multi_buffer_list*)arg);
948 
949 		case B_MULTI_BUFFER_EXCHANGE:
950 			return buffer_exchange(audioGroup, (multi_buffer_info*)arg);
951 		case B_MULTI_BUFFER_FORCE_STOP:
952 			return buffer_force_stop(audioGroup);
953 
954 		case B_MULTI_GET_EVENT_INFO:
955 		case B_MULTI_SET_EVENT_INFO:
956 		case B_MULTI_GET_EVENT:
957 		case B_MULTI_GET_CHANNEL_FORMATS:
958 		case B_MULTI_SET_CHANNEL_FORMATS:
959 		case B_MULTI_SET_BUFFERS:
960 		case B_MULTI_SET_START_TIME:
961 			return B_ERROR;
962 	}
963 
964 	return B_BAD_VALUE;
965 }
966