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