xref: /haiku/src/add-ons/kernel/drivers/audio/hda/hda_multi_audio.cpp (revision adb0d19d561947362090081e81d90dde59142026)
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 = mmci->controls;
465 	if (mmci->control_count < 24)
466 		return B_ERROR;
467 
468 	if (hda_create_controls_list(audioGroup->multi) < B_OK)
469 		return B_ERROR;
470 	for (uint32 i = 0; i < audioGroup->multi->control_count; i++) {
471 		mmc[i] = audioGroup->multi->controls[i].mix_control;
472 	}
473 
474 	mmci->control_count = audioGroup->multi->control_count;
475 	return B_OK;
476 }
477 
478 
479 static status_t
480 list_mix_connections(hda_audio_group* audioGroup,
481 	multi_mix_connection_info* data)
482 {
483 	data->actual_count = 0;
484 	return B_OK;
485 }
486 
487 
488 static status_t
489 list_mix_channels(hda_audio_group* audioGroup, multi_mix_channel_info *data)
490 {
491 	return B_OK;
492 }
493 
494 
495 static void
496 get_control_gain_mute(hda_audio_group* audioGroup, hda_multi_mixer_control *control, uint32 *resp)
497 {
498 	uint32 verb[2];
499 	verb[0] = MAKE_VERB(audioGroup->codec->addr,
500 		control->nid,
501 		VID_GET_AMPLIFIER_GAIN_MUTE,
502 		(control->input ? AMP_GET_INPUT : AMP_GET_OUTPUT)
503 		| AMP_GET_LEFT_CHANNEL | AMP_GET_INPUT_INDEX(control->index));
504 	verb[1] = MAKE_VERB(audioGroup->codec->addr,
505 		control->nid,
506 		VID_GET_AMPLIFIER_GAIN_MUTE,
507 		(control->input ? AMP_GET_INPUT : AMP_GET_OUTPUT)
508 		| AMP_GET_RIGHT_CHANNEL | AMP_GET_INPUT_INDEX(control->index));
509 	hda_send_verbs(audioGroup->codec, verb, resp, 2);
510 }
511 
512 
513 static status_t
514 get_mix(hda_audio_group* audioGroup, multi_mix_value_info * mmvi)
515 {
516 	uint32 id;
517 	hda_multi_mixer_control *control = NULL;
518 	for (int32 i = 0; i < mmvi->item_count; i++) {
519 		id = mmvi->values[i].id - MULTI_CONTROL_FIRSTID;
520 		if (id < 0 || id >= audioGroup->multi->control_count) {
521 			dprintf("hda: get_mix : invalid control id requested : %li\n", id);
522 			continue;
523 		}
524 		control = &audioGroup->multi->controls[id];
525 
526 		if (control->mix_control.flags & (B_MULTI_MIX_GAIN | B_MULTI_MIX_ENABLE)) {
527 			uint32 resp[2];
528 			get_control_gain_mute(audioGroup, control, resp);
529 			if (control->mix_control.flags & B_MULTI_MIX_ENABLE) {
530 				mmvi->values[i].enable = (resp[0] & AMP_MUTE) != 0;
531 				TRACE("get_mix: %ld mute: %d\n", control->nid, mmvi->values[i].enable);
532 			} else if (control->mix_control.flags & B_MULTI_MIX_GAIN) {
533 				uint32 value;
534 				if (control->mix_control.master == MULTI_CONTROL_MASTERID)
535 					value = resp[0] & AMP_GAIN_MASK;
536 				else
537 					value = resp[1] & AMP_GAIN_MASK;
538 				mmvi->values[i].gain = (0.0 + value - AMP_CAP_OFFSET(control->capabilities))
539 						* AMP_CAP_STEP_SIZE(control->capabilities);
540 				TRACE("get_mix: %ld gain: %f (%ld)\n", control->nid, mmvi->values[i].gain, value);
541 			}
542 
543 
544 		}
545 
546 		/*if (control->mix_control.flags & B_MULTI_MIX_MUX && control->get) {
547 			float values[1];
548 			control->get(audioGroup, control, values);
549 			mmvi->values[i].mux = (int32)values[0];
550 		}*/
551 	}
552 	return B_OK;
553 }
554 
555 
556 static status_t
557 set_mix(hda_audio_group* audioGroup, multi_mix_value_info * mmvi)
558 {
559 	uint32 id;
560 	hda_multi_mixer_control *control = NULL;
561 	for (int32 i = 0; i < mmvi->item_count; i++) {
562 		id = mmvi->values[i].id - MULTI_CONTROL_FIRSTID;
563 		if (id < 0 || id >= audioGroup->multi->control_count) {
564 			dprintf("set_mix : invalid control id requested : %li\n", id);
565 			continue;
566 		}
567 		control = &audioGroup->multi->controls[id];
568 
569 		if (control->mix_control.flags & B_MULTI_MIX_ENABLE) {
570 			control->mute = (mmvi->values[i].enable ? AMP_MUTE : 0);
571 			TRACE("set_mix: %ld mute: %lx\n", control->nid, control->mute);
572 			uint32 resp[2];
573 			get_control_gain_mute(audioGroup, control, resp);
574 
575 			uint32 verb[2];
576 			verb[0] = MAKE_VERB(audioGroup->codec->addr,
577 				control->nid,
578 				VID_SET_AMPLIFIER_GAIN_MUTE,
579 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
580 				| AMP_SET_LEFT_CHANNEL
581 				| AMP_SET_INPUT_INDEX(control->index)
582 				| control->mute
583 				| resp[0] & AMP_GAIN_MASK);
584 			TRACE("set_mix: sending verb to %ld: %lx %lx %x %lx\n", control->nid,
585 				control->mute, resp[0] & AMP_GAIN_MASK, control->input,
586 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
587 				| AMP_SET_LEFT_CHANNEL
588 				| AMP_SET_INPUT_INDEX(control->index)
589 				| control->mute
590 				| resp[0] & AMP_GAIN_MASK);
591 			verb[1] = MAKE_VERB(audioGroup->codec->addr,
592 				control->nid,
593 				VID_SET_AMPLIFIER_GAIN_MUTE,
594 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
595 				| AMP_SET_RIGHT_CHANNEL
596 				| AMP_SET_INPUT_INDEX(control->index)
597 				| control->mute
598 				| resp[1] & AMP_GAIN_MASK);
599 			TRACE("set_mix: ctrl2 sending verb to %ld: %lx %lx %x\n", control->nid,
600 				control->mute, resp[1] & AMP_GAIN_MASK, control->input);
601 			hda_send_verbs(audioGroup->codec, verb, NULL, 2);
602 		} else if (control->mix_control.flags & B_MULTI_MIX_GAIN) {
603 			hda_multi_mixer_control *control2 = NULL;
604 			if (i+1<mmvi->item_count) {
605 				id = mmvi->values[i + 1].id - MULTI_CONTROL_FIRSTID;
606 				if (id < 0 || id >= audioGroup->multi->control_count) {
607 					dprintf("set_mix : invalid control id requested : %li\n", id);
608 				} else {
609 					control2 = &audioGroup->multi->controls[id];
610 					if (control2->mix_control.master != control->mix_control.id)
611 						control2 = NULL;
612 				}
613 			}
614 
615 			if (control->mix_control.master == MULTI_CONTROL_MASTERID)
616 				control->gain = (uint32)(mmvi->values[i].gain / AMP_CAP_STEP_SIZE(control->capabilities)
617 					+ AMP_CAP_OFFSET(control->capabilities));
618 
619 			if (control2 && control2->mix_control.master != MULTI_CONTROL_MASTERID)
620 				control2->gain = (uint32)(mmvi->values[i+1].gain / AMP_CAP_STEP_SIZE(control2->capabilities)
621 					+ AMP_CAP_OFFSET(control2->capabilities));
622 			TRACE("set_mix: %ld gain: %lx and %ld gain: %lx\n",
623 				control->nid, control->gain, control2->nid, control2->gain);
624 			uint32 resp[2];
625 			get_control_gain_mute(audioGroup, control, resp);
626 			control->mute = resp[0] & AMP_MUTE;
627 			if (control2)
628 				control2->mute = resp[1] & AMP_MUTE;
629 
630 			uint32 verb[2];
631 			verb[0] = MAKE_VERB(audioGroup->codec->addr,
632 				control->nid,
633 				VID_SET_AMPLIFIER_GAIN_MUTE,
634 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
635 				| AMP_SET_LEFT_CHANNEL
636 				| AMP_SET_INPUT_INDEX(control->index)
637 				| (control->mute & AMP_MUTE)
638 				| (control->gain & AMP_GAIN_MASK));
639 			TRACE("set_mix: sending verb to %ld: %lx %lx %x %lx\n", control->nid,
640 				control->mute, control->gain, control->input,
641 				(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
642 				| AMP_SET_LEFT_CHANNEL
643 				| AMP_SET_INPUT_INDEX(control->index)
644 				| (control->mute & AMP_MUTE)
645 				| (control->gain & AMP_GAIN_MASK));
646 			if (control2) {
647 				verb[1] = MAKE_VERB(audioGroup->codec->addr,
648 					control2->nid,
649 					VID_SET_AMPLIFIER_GAIN_MUTE,
650 					(control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
651 					| AMP_SET_RIGHT_CHANNEL
652 					| AMP_SET_INPUT_INDEX(control->index)
653 					| (control2->mute & AMP_MUTE)
654 					| (control2->gain & AMP_GAIN_MASK));
655 				TRACE("set_mix: ctrl2 sending verb to %ld: %lx %lx %x\n", control2->nid,
656 					control2->mute, control2->gain, control2->input);
657 			}
658 			hda_send_verbs(audioGroup->codec, verb, NULL, control2 ? 2 : 1);
659 
660 			if (control2)
661 				i++;
662 		}
663 
664 		/*if (control->mix_control.flags & B_MULTI_MIX_MUX && control->set) {
665 			float values[1];
666 
667 			values[0] = (float)mmvi->values[i].mux;
668 			control->set(card, control->channel, control->type, values);
669 		}*/
670 	}
671 	return B_OK;
672 }
673 
674 
675 static uint32
676 default_buffer_length_for_rate(uint32 rate)
677 {
678 	// keep the latency about the same as 2048 frames per buffer at 44100 kHz
679 	switch (rate) {
680 	case B_SR_8000:
681 		return 512;
682 	case B_SR_11025:
683 		return 512;
684 	case B_SR_16000:
685 		return 1024;
686 	case B_SR_22050:
687 		return 1024;
688 	case B_SR_32000:
689 		return 2048;
690 	case B_SR_44100:
691 		return 2048;
692 	case B_SR_48000:
693 		return 2048;
694 	case B_SR_88200:
695 		return 4096;
696 	case B_SR_96000:
697 		return 6144;
698 	case B_SR_176400:
699 		return 8192;
700 	case B_SR_192000:
701 		return 10240;
702 	case B_SR_384000:
703 		return 16384;
704 	}
705 	return 2048;
706 };
707 
708 
709 static status_t
710 get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
711 {
712 	TRACE("playback: %ld buffers, %ld channels, %ld samples\n",
713 		data->request_playback_buffers, data->request_playback_channels,
714 		data->request_playback_buffer_size);
715 	TRACE("record: %ld buffers, %ld channels, %ld samples\n",
716 		data->request_record_buffers, data->request_record_channels,
717 		data->request_record_buffer_size);
718 
719 	/* Determine what buffers we return given the request */
720 
721 	data->return_playback_buffers = data->request_playback_buffers;
722 	data->return_playback_channels = data->request_playback_channels;
723 	data->return_playback_buffer_size = data->request_playback_buffer_size;
724 	data->return_record_buffers = data->request_record_buffers;
725 	data->return_record_channels = data->request_record_channels;
726 	data->return_record_buffer_size = data->request_record_buffer_size;
727 
728 	/* Workaround for Haiku multi_audio API, since it prefers to let the
729 	   driver pick values, while the BeOS multi_audio actually gives the
730 	   user's defaults. */
731 	if (data->return_playback_buffers > STREAM_MAX_BUFFERS
732 		|| data->return_playback_buffers < STREAM_MIN_BUFFERS)
733 		data->return_playback_buffers = STREAM_MIN_BUFFERS;
734 
735 	if (data->return_record_buffers > STREAM_MAX_BUFFERS
736 		|| data->return_record_buffers < STREAM_MIN_BUFFERS)
737 		data->return_record_buffers = STREAM_MIN_BUFFERS;
738 
739 	if (data->return_playback_buffer_size == 0) {
740 		data->return_playback_buffer_size = default_buffer_length_for_rate(
741 			audioGroup->playback_stream->sample_rate);
742 	}
743 
744 	if (data->return_record_buffer_size == 0) {
745 		data->return_record_buffer_size = default_buffer_length_for_rate(
746 				audioGroup->record_stream->sample_rate);
747 	}
748 
749 	/* ... from here on, we can assume again that a reasonable request is
750 	   being made */
751 
752 	data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD;
753 
754 	/* Copy the settings into the streams */
755 
756 	if (audioGroup->playback_stream != NULL) {
757 		audioGroup->playback_stream->num_buffers = data->return_playback_buffers;
758 		audioGroup->playback_stream->num_channels = data->return_playback_channels;
759 		audioGroup->playback_stream->buffer_length
760 			= data->return_playback_buffer_size;
761 
762 		status_t status = hda_stream_setup_buffers(audioGroup,
763 			audioGroup->playback_stream, "Playback");
764 		if (status != B_OK) {
765 			dprintf("hda: Error setting up playback buffers: %s\n",
766 				strerror(status));
767 			return status;
768 		}
769 	}
770 
771 	if (audioGroup->record_stream != NULL) {
772 		audioGroup->record_stream->num_buffers = data->return_record_buffers;
773 		audioGroup->record_stream->num_channels = data->return_record_channels;
774 		audioGroup->record_stream->buffer_length
775 			= data->return_record_buffer_size;
776 
777 		status_t status = hda_stream_setup_buffers(audioGroup,
778 			audioGroup->record_stream, "Recording");
779 		if (status != B_OK) {
780 			dprintf("hda: Error setting up recording buffers: %s\n",
781 				strerror(status));
782 			return status;
783 		}
784 	}
785 
786 	/* Setup data structure for multi_audio API... */
787 
788 	if (audioGroup->playback_stream != NULL) {
789 		uint32 playbackSampleSize = audioGroup->playback_stream->sample_size;
790 
791 		for (int32 i = 0; i < data->return_playback_buffers; i++) {
792 			for (int32 channelIndex = 0;
793 					channelIndex < data->return_playback_channels; channelIndex++) {
794 				data->playback_buffers[i][channelIndex].base
795 					= (char*)audioGroup->playback_stream->buffers[i]
796 						+ playbackSampleSize * channelIndex;
797 				data->playback_buffers[i][channelIndex].stride
798 					= playbackSampleSize * data->return_playback_channels;
799 			}
800 		}
801 	}
802 
803 	if (audioGroup->record_stream != NULL) {
804 		uint32 recordSampleSize = audioGroup->record_stream->sample_size;
805 
806 		for (int32 i = 0; i < data->return_record_buffers; i++) {
807 			for (int32 channelIndex = 0;
808 					channelIndex < data->return_record_channels; channelIndex++) {
809 				data->record_buffers[i][channelIndex].base
810 					= (char*)audioGroup->record_stream->buffers[i]
811 						+ recordSampleSize * channelIndex;
812 				data->record_buffers[i][channelIndex].stride
813 					= recordSampleSize * data->return_record_channels;
814 			}
815 		}
816 	}
817 
818 	return B_OK;
819 }
820 
821 
822 /*! playback_buffer_cycle is the buffer we want to have played */
823 static status_t
824 buffer_exchange(hda_audio_group* audioGroup, multi_buffer_info* data)
825 {
826 	cpu_status status;
827 	status_t err;
828 	multi_buffer_info buffer_info;
829 
830 	if (audioGroup->playback_stream == NULL)
831 		return B_ERROR;
832 
833 	if (!audioGroup->playback_stream->running) {
834 		hda_stream_start(audioGroup->codec->controller,
835 			audioGroup->playback_stream);
836 	}
837 	if (audioGroup->record_stream && !audioGroup->record_stream->running) {
838 		hda_stream_start(audioGroup->codec->controller,
839 			audioGroup->record_stream);
840 	}
841 
842 #ifdef __HAIKU__
843 	if (user_memcpy(&buffer_info, data, sizeof(buffer_info)) < B_OK)
844 		return B_BAD_ADDRESS;
845 #else
846 	memcpy(&buffer_info, data, sizeof(buffer_info));
847 #endif
848 
849 	/* do playback */
850 	err = acquire_sem_etc(audioGroup->playback_stream->buffer_ready_sem,
851 		1, B_CAN_INTERRUPT, 0);
852 	if (err != B_OK) {
853 		dprintf("%s: Error waiting for playback buffer to finish (%s)!\n", __func__,
854 			strerror(err));
855 		return err;
856 	}
857 
858 	status = disable_interrupts();
859 	acquire_spinlock(&audioGroup->playback_stream->lock);
860 
861 	buffer_info.playback_buffer_cycle = audioGroup->playback_stream->buffer_cycle;
862 	buffer_info.played_real_time = audioGroup->playback_stream->real_time;
863 	buffer_info.played_frames_count = audioGroup->playback_stream->frames_count;
864 
865 	release_spinlock(&audioGroup->playback_stream->lock);
866 
867 	if (audioGroup->record_stream) {
868 		acquire_spinlock(&audioGroup->record_stream->lock);
869 		buffer_info.record_buffer_cycle = audioGroup->record_stream->buffer_cycle;
870 		buffer_info.recorded_real_time = audioGroup->record_stream->real_time;
871 		buffer_info.recorded_frames_count = audioGroup->record_stream->frames_count;
872 		release_spinlock(&audioGroup->record_stream->lock);
873 	}
874 
875 	restore_interrupts(status);
876 
877 #ifdef __HAIKU__
878 	if (user_memcpy(data, &buffer_info, sizeof(buffer_info)) < B_OK)
879 		return B_BAD_ADDRESS;
880 #else
881 	memcpy(data, &buffer_info, sizeof(buffer_info));
882 #endif
883 
884 #if 0
885 	static int debug_buffers_exchanged = 0;
886 
887 	debug_buffers_exchanged++;
888 	if (((debug_buffers_exchanged % 100) == 1) && (debug_buffers_exchanged < 1111)) {
889 		dprintf("%s: %d buffers processed\n", __func__, debug_buffers_exchanged);
890 	}
891 #endif
892 	return B_OK;
893 }
894 
895 
896 static status_t
897 buffer_force_stop(hda_audio_group* audioGroup)
898 {
899 	if (audioGroup->playback_stream != NULL) {
900 		hda_stream_stop(audioGroup->codec->controller,
901 			audioGroup->playback_stream);
902 	}
903 	if (audioGroup->record_stream != NULL) {
904 		hda_stream_stop(audioGroup->codec->controller,
905 			audioGroup->record_stream);
906 	}
907 	//hda_stream_stop(audioGroup->codec->controller, audioGroup->record_stream);
908 
909 	return B_OK;
910 }
911 
912 
913 status_t
914 multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
915 {
916 	hda_codec* codec = (hda_codec*)cookie;
917 	hda_audio_group* audioGroup;
918 
919 	/* FIXME: We should simply pass the audioGroup into here... */
920 	if (!codec || codec->num_audio_groups == 0)
921 		return ENODEV;
922 
923 	audioGroup = codec->audio_groups[0];
924 
925 	// TODO: make userland-safe when built for Haiku!
926 
927 	switch (op) {
928 		case B_MULTI_GET_DESCRIPTION:
929 		{
930 #ifdef __HAIKU__
931 			multi_description description;
932 			multi_channel_info channels[16];
933 			multi_channel_info* originalChannels;
934 
935 			if (user_memcpy(&description, arg, sizeof(multi_description))
936 					!= B_OK)
937 				return B_BAD_ADDRESS;
938 
939 			originalChannels = description.channels;
940 			description.channels = channels;
941 			if (description.request_channel_count > 16)
942 				description.request_channel_count = 16;
943 
944 			status_t status = get_description(audioGroup, &description);
945 			if (status != B_OK)
946 				return status;
947 
948 			description.channels = originalChannels;
949 			if (user_memcpy(arg, &description, sizeof(multi_description))
950 					!= B_OK)
951 				return B_BAD_ADDRESS;
952 			return user_memcpy(originalChannels, channels, sizeof(multi_channel_info)
953 					* description.request_channel_count);
954 #else
955 			return get_description(audioGroup, (multi_description*)arg);
956 #endif
957 		}
958 
959 		case B_MULTI_GET_ENABLED_CHANNELS:
960 			return get_enabled_channels(audioGroup, (multi_channel_enable*)arg);
961 		case B_MULTI_SET_ENABLED_CHANNELS:
962 			return B_OK;
963 
964 		case B_MULTI_GET_GLOBAL_FORMAT:
965 			return get_global_format(audioGroup, (multi_format_info*)arg);
966 		case B_MULTI_SET_GLOBAL_FORMAT:
967 			return set_global_format(audioGroup, (multi_format_info*)arg);
968 
969 		case B_MULTI_LIST_MIX_CHANNELS:
970 			return list_mix_channels(audioGroup, (multi_mix_channel_info*)arg);
971 		case B_MULTI_LIST_MIX_CONTROLS:
972 			return list_mix_controls(audioGroup, (multi_mix_control_info*)arg);
973 		case B_MULTI_LIST_MIX_CONNECTIONS:
974 			return list_mix_connections(audioGroup,
975 				(multi_mix_connection_info*)arg);
976 		case B_MULTI_GET_MIX:
977 			return get_mix(audioGroup, (multi_mix_value_info *)arg);
978 		case B_MULTI_SET_MIX:
979 			return set_mix(audioGroup, (multi_mix_value_info *)arg);
980 
981 		case B_MULTI_GET_BUFFERS:
982 			return get_buffers(audioGroup, (multi_buffer_list*)arg);
983 
984 		case B_MULTI_BUFFER_EXCHANGE:
985 			return buffer_exchange(audioGroup, (multi_buffer_info*)arg);
986 		case B_MULTI_BUFFER_FORCE_STOP:
987 			return buffer_force_stop(audioGroup);
988 
989 		case B_MULTI_GET_EVENT_INFO:
990 		case B_MULTI_SET_EVENT_INFO:
991 		case B_MULTI_GET_EVENT:
992 		case B_MULTI_GET_CHANNEL_FORMATS:
993 		case B_MULTI_SET_CHANNEL_FORMATS:
994 		case B_MULTI_SET_BUFFERS:
995 		case B_MULTI_SET_START_TIME:
996 			return B_ERROR;
997 	}
998 
999 	return B_BAD_VALUE;
1000 }
1001