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