xref: /haiku/src/add-ons/kernel/drivers/audio/ac97/geode/geode_multi.cpp (revision 9f3bdf3d039430b5172c424def20ce5d9f7367d4)
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 
26 static 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 
42 static int32
43 format2size(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 
63 static status_t
64 get_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 
119 static status_t
120 get_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 
132 static status_t
133 get_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 
159 static status_t
160 set_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 
187 static void
188 geode_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 
245 static void
246 geode_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 
317 static int32
318 create_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 
334 static status_t
335 create_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 
526 static status_t
527 list_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 
544 static status_t
545 list_mix_connections(geode_controller* controller,
546 	multi_mix_connection_info* data)
547 {
548 	data->actual_count = 0;
549 	return B_OK;
550 }
551 
552 
553 static status_t
554 list_mix_channels(geode_controller* controller, multi_mix_channel_info *data)
555 {
556 	return B_OK;
557 }
558 
559 
560 static status_t
561 get_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 
598 static status_t
599 set_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 
661 static status_t
662 get_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 */
771 static status_t
772 buffer_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 
840 static status_t
841 buffer_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 
854 status_t
855 multi_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