xref: /haiku/src/add-ons/kernel/drivers/audio/echo/multi.cpp (revision 079c69cbfd7cd3c97baae91332251c8388a8bb02)
1 /*
2  * EchoGals/Echo24 BeOS Driver for Echo audio cards
3  *
4  * Copyright (c) 2003, Jerome Duval (jerome.duval@free.fr)
5  *
6  * Original code : BeOS Driver for Intel ICH AC'97 Link interface
7  * Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de>
8  *
9  * All rights reserved.
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice,
14  *   this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  *   this list of conditions and the following disclaimer in the documentation
17  *   and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31 
32 #include <OS.h>
33 #include <MediaDefs.h>
34 #include "debug.h"
35 #include "hmulti_audio.h"
36 #include "multi.h"
37 
38 //#define DEBUG 1
39 
40 #include "echo.h"
41 #include "util.h"
42 
43 typedef enum {
44         B_MIX_GAIN = 1 << 0,
45         B_MIX_MUTE = 1 << 1,
46         B_MIX_NOMINAL = 1 << 2
47 } mixer_type;
48 
49 static void
50 echo_channel_get_mix(void *card, MIXER_AUDIO_CHANNEL channel, int32 type, float *values) {
51 
52 	echo_dev *dev = (echo_dev*) card;
53 	MIXER_MULTI_FUNCTION multi_function[2];
54 	PMIXER_FUNCTION function = multi_function[0].MixerFunction;
55 	INT32 size = ComputeMixerMultiFunctionSize(2);
56 	function[0].Channel = channel;
57 	function[1].Channel = channel;
58 	function[1].Channel.wChannel++;
59 	switch (type) {
60 	case B_MIX_GAIN:
61 		function[0].iFunction = function[1].iFunction = MXF_GET_LEVEL;
62 		break;
63 	case B_MIX_MUTE:
64 		function[0].iFunction = function[1].iFunction = MXF_GET_MUTE;
65 		break;
66 	case B_MIX_NOMINAL:
67 		function[0].iFunction = function[1].iFunction = MXF_GET_NOMINAL;
68 		break;
69 	}
70 
71 	multi_function[0].iCount = 2;
72 	dev->pEG->ProcessMixerMultiFunction(multi_function, size);
73 
74 	if (function[0].RtnStatus == ECHOSTATUS_OK) {
75 		if (type == B_MIX_GAIN) {
76 			values[0] = (float)function[0].Data.iLevel / 256;
77 			values[1] = (float)function[1].Data.iLevel / 256;
78 		} else if (type == B_MIX_MUTE) {
79 			values[0] = function[0].Data.bMuteOn ? 1.0 : 0.0;
80 		} else {
81 			values[0] = function[0].Data.iNominal == 4 ? 1.0 : 0.0;
82 		}
83 		PRINT(("echo_channel_get_mix iLevel: %ld, %d, %ld\n", function[0].Data.iLevel, channel.wChannel, channel.dwType));
84 	}
85 
86 }
87 
88 static void
89 echo_channel_set_mix(void *card, MIXER_AUDIO_CHANNEL channel, int32 type, float *values) {
90 	echo_dev *dev = (echo_dev*) card;
91 	MIXER_MULTI_FUNCTION multi_function[2];
92 	PMIXER_FUNCTION function = multi_function[0].MixerFunction;
93         INT32 size = ComputeMixerMultiFunctionSize(2);
94         function[0].Channel = channel;
95 	function[1].Channel = channel;
96 	function[1].Channel.wChannel++;
97 	if (type == B_MIX_GAIN) {
98 		function[0].Data.iLevel = (int)(values[0] * 256);
99         	function[0].iFunction = MXF_SET_LEVEL;
100 		function[1].Data.iLevel = (int)(values[1] * 256);
101 		function[1].iFunction = MXF_SET_LEVEL;
102 	} else if (type == B_MIX_MUTE) {
103 		function[0].Data.bMuteOn = values[0] == 1.0;
104 		function[0].iFunction = MXF_SET_MUTE;
105 		function[1].Data.bMuteOn = values[0] == 1.0;
106 		function[1].iFunction = MXF_SET_MUTE;
107 	} else {
108 		function[0].Data.iNominal = values[0] == 1.0 ? 4 : -10;
109                 function[0].iFunction = MXF_SET_NOMINAL;
110                 function[1].Data.iNominal = values[0] == 1.0 ? 4 : -10;
111                 function[1].iFunction = MXF_SET_NOMINAL;
112 	}
113 
114 	multi_function[0].iCount = 2;
115         dev->pEG->ProcessMixerMultiFunction(multi_function, size);
116 
117         if (function[0].RtnStatus == ECHOSTATUS_OK) {
118                 PRINT(("echo_channel_set_mix OK: %ld, %d, %ld\n", function[0].Data.iLevel, channel.wChannel, channel.dwType));
119         }
120 
121 }
122 
123 
124 static int32
125 echo_create_group_control(multi_dev *multi, uint32 *index, int32 parent,
126         enum strind_id string, const char* name) {
127         uint32 i = *index;
128         (*index)++;
129         multi->controls[i].mix_control.id = MULTI_CONTROL_FIRSTID + i;
130         multi->controls[i].mix_control.parent = parent;
131         multi->controls[i].mix_control.flags = B_MULTI_MIX_GROUP;
132         multi->controls[i].mix_control.master = MULTI_CONTROL_MASTERID;
133         multi->controls[i].mix_control.string = string;
134         if(name)
135                 strcpy(multi->controls[i].mix_control.name, name);
136 
137         return multi->controls[i].mix_control.id;
138 }
139 
140 static void
141 echo_create_channel_control(multi_dev *multi, uint32 *index, int32 parent, int32 string,
142 	MIXER_AUDIO_CHANNEL channel, bool nominal) {
143 	uint32 i = *index, id;
144 	multi_mixer_control control;
145 
146 	control.mix_control.master = MULTI_CONTROL_MASTERID;
147 	control.mix_control.parent = parent;
148 	control.channel = channel;
149 	control.get = &echo_channel_get_mix;
150 	control.set = &echo_channel_set_mix;
151 	control.mix_control.gain.min_gain = -128;
152 	control.mix_control.gain.max_gain = 6;
153 	control.mix_control.gain.granularity = 0.5;
154 
155 	control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
156 	control.mix_control.flags = B_MULTI_MIX_ENABLE;
157 	control.mix_control.string = S_MUTE;
158 	control.type = B_MIX_MUTE;
159 	multi->controls[i] = control;
160 	i++;
161 
162 	control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
163 	control.mix_control.flags = B_MULTI_MIX_GAIN;
164 	control.mix_control.string = S_null;
165 	control.type = B_MIX_GAIN;
166 	strcpy(control.mix_control.name, "Gain");
167 	multi->controls[i] = control;
168 	id = control.mix_control.id;
169 	i++;
170 
171 	// second channel
172 	control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
173 	control.mix_control.master = id;
174 	multi->controls[i] = control;
175 	i++;
176 
177 	// nominal level (+4/-10)
178 	if (nominal) {
179 		control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
180 		control.mix_control.master = MULTI_CONTROL_MASTERID;
181 		control.mix_control.flags = B_MULTI_MIX_ENABLE;
182 		control.mix_control.string = S_null;
183 		control.type = B_MIX_NOMINAL;
184 		strcpy(control.mix_control.name, "+4dB");
185 		multi->controls[i] = control;
186 		i++;
187 	}
188 
189 	*index = i;
190 }
191 
192 
193 static status_t
194 echo_create_controls_list(multi_dev *multi)
195 {
196 	uint32 	i = 0, index = 0, parent, parent2;
197 	echo_dev *card = (echo_dev*)multi->card;
198 
199 	parent = echo_create_group_control(multi, &index, 0, S_OUTPUT, NULL);
200 
201 	MIXER_AUDIO_CHANNEL channel;
202 	channel.wCardId = 0;
203 	channel.dwType = ECHO_BUS_OUT;
204 	for (i=0; i < card->caps.wNumBussesOut / 2; i++) {
205 		channel.wChannel = i * 2;
206 		parent2 = echo_create_group_control(multi, &index, parent, S_null, "Output");
207 
208 		echo_create_channel_control(multi, &index, parent2, 0, channel,
209 			card->caps.dwBusOutCaps[i*2] & ECHOCAPS_NOMINAL_LEVEL);
210 	}
211 
212 	parent = echo_create_group_control(multi, &index, 0, S_INPUT, NULL);
213 
214 	channel.dwType = ECHO_BUS_IN;
215 	for (i=0; i < card->caps.wNumBussesIn / 2; i++) {
216 		channel.wChannel = i * 2;
217 
218 		parent2 = echo_create_group_control(multi, &index, parent, S_null, "Input");
219 
220 		echo_create_channel_control(multi, &index, parent2, 0, channel,
221 			card->caps.dwBusInCaps[i*2] & ECHOCAPS_NOMINAL_LEVEL);
222 	}
223 
224 	multi->control_count = index;
225 	PRINT(("multi->control_count %lu\n", multi->control_count));
226 	return B_OK;
227 }
228 
229 static status_t
230 echo_get_mix(echo_dev *card, multi_mix_value_info * MMVI)
231 {
232 	int32 i;
233 	uint32 id;
234 	multi_mixer_control *control = NULL;
235 	for(i=0; i<MMVI->item_count; i++) {
236 		id = MMVI->values[i].id - MULTI_CONTROL_FIRSTID;
237 		if(id < 0 || id >= card->multi.control_count) {
238 			PRINT(("echo_get_mix : invalid control id requested : %li\n", id));
239 			continue;
240 		}
241 		control = &card->multi.controls[id];
242 
243 		if(control->mix_control.flags & B_MULTI_MIX_GAIN) {
244 			if(control->get) {
245 				float values[2];
246 				control->get(card, control->channel, control->type, values);
247 				if(control->mix_control.master == MULTI_CONTROL_MASTERID)
248 					MMVI->values[i].gain = values[0];
249 				else
250 					MMVI->values[i].gain = values[1];
251 			}
252 		}
253 
254 		if(control->mix_control.flags & B_MULTI_MIX_ENABLE && control->get) {
255 			float values[1];
256 			control->get(card, control->channel, control->type, values);
257 			MMVI->values[i].enable = (values[0] == 1.0);
258 		}
259 
260 		if(control->mix_control.flags & B_MULTI_MIX_MUX && control->get) {
261 			float values[1];
262 			control->get(card, control->channel, control->type, values);
263 			MMVI->values[i].mux = (int32)values[0];
264 		}
265 	}
266 	return B_OK;
267 }
268 
269 static status_t
270 echo_set_mix(echo_dev *card, multi_mix_value_info * MMVI)
271 {
272 	int32 i;
273 	uint32 id;
274 	multi_mixer_control *control = NULL;
275 	for(i=0; i<MMVI->item_count; i++) {
276 		id = MMVI->values[i].id - MULTI_CONTROL_FIRSTID;
277 		if(id < 0 || id >= card->multi.control_count) {
278 			PRINT(("echo_set_mix : invalid control id requested : %li\n", id));
279 			continue;
280 		}
281 		control = &card->multi.controls[id];
282 
283 		if(control->mix_control.flags & B_MULTI_MIX_GAIN) {
284 			multi_mixer_control *control2 = NULL;
285 			if(i+1<MMVI->item_count) {
286 				id = MMVI->values[i + 1].id - MULTI_CONTROL_FIRSTID;
287 				if(id < 0 || id >= card->multi.control_count) {
288 					PRINT(("echo_set_mix : invalid control id requested : %li\n", id));
289 				} else {
290 					control2 = &card->multi.controls[id];
291 					if(control2->mix_control.master != control->mix_control.id)
292 						control2 = NULL;
293 				}
294 			}
295 
296 			if(control->set) {
297 				float values[2];
298 				values[0] = 0.0;
299 				values[1] = 0.0;
300 
301 				if(control->mix_control.master == MULTI_CONTROL_MASTERID)
302 					values[0] = MMVI->values[i].gain;
303 				else
304 					values[1] = MMVI->values[i].gain;
305 
306 				if(control2 && control2->mix_control.master != MULTI_CONTROL_MASTERID)
307 					values[1] = MMVI->values[i+1].gain;
308 
309 				control->set(card, control->channel, control->type, values);
310 			}
311 
312 			if(control2)
313 				i++;
314 		}
315 
316 		if(control->mix_control.flags & B_MULTI_MIX_ENABLE && control->set) {
317 			float values[1];
318 
319 			values[0] = MMVI->values[i].enable ? 1.0 : 0.0;
320 			control->set(card, control->channel, control->type, values);
321 		}
322 
323 		if(control->mix_control.flags & B_MULTI_MIX_MUX && control->set) {
324 			float values[1];
325 
326 			values[0] = (float)MMVI->values[i].mux;
327 			control->set(card, control->channel, control->type, values);
328 		}
329 	}
330 	return B_OK;
331 }
332 
333 static status_t
334 echo_list_mix_controls(echo_dev *card, multi_mix_control_info * MMCI)
335 {
336 	multi_mix_control	*MMC;
337 	uint32 i;
338 
339 	MMC = MMCI->controls;
340 	if(MMCI->control_count < 24)
341 		return B_ERROR;
342 
343 	if(echo_create_controls_list(&card->multi) < B_OK)
344 		return B_ERROR;
345 	for(i=0; i<card->multi.control_count; i++) {
346 		MMC[i] = card->multi.controls[i].mix_control;
347 	}
348 
349 	MMCI->control_count = card->multi.control_count;
350 	return B_OK;
351 }
352 
353 static status_t
354 echo_list_mix_connections(echo_dev *card, multi_mix_connection_info * data)
355 {
356 	return B_ERROR;
357 }
358 
359 static status_t
360 echo_list_mix_channels(echo_dev *card, multi_mix_channel_info *data)
361 {
362 	return B_ERROR;
363 }
364 
365 /*multi_channel_info chans[] = {
366 {  0, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
367 {  1, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
368 {  2, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
369 {  3, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
370 {  4, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
371 {  5, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
372 {  6, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
373 {  7, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
374 {  8, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
375 {  9, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
376 {  10, B_MULTI_INPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
377 {  11, B_MULTI_INPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
378 };*/
379 
380 /*multi_channel_info chans[] = {
381 {  0, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
382 {  1, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
383 {  2, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_SURROUND_BUS, 0 },
384 {  3, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_SURROUND_BUS, 0 },
385 {  4, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_REARLEFT | B_CHANNEL_SURROUND_BUS, 0 },
386 {  5, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_REARRIGHT | B_CHANNEL_SURROUND_BUS, 0 },
387 {  6, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
388 {  7, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
389 {  8, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
390 {  9, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
391 {  10, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
392 {  11, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
393 {  12, B_MULTI_INPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
394 {  13, B_MULTI_INPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
395 };*/
396 
397 
398 static void
399 echo_create_channels_list(multi_dev *multi)
400 {
401 	echo_stream *stream;
402 	int32 mode;
403 	uint32 index, i, designations;
404 	multi_channel_info *chans;
405 	uint32 chan_designations[] = {
406 		B_CHANNEL_LEFT,
407 		B_CHANNEL_RIGHT,
408 		B_CHANNEL_REARLEFT,
409 		B_CHANNEL_REARRIGHT,
410 		B_CHANNEL_CENTER,
411 		B_CHANNEL_SUB
412 	};
413 
414 	chans = multi->chans;
415 	index = 0;
416 
417 	for(mode=ECHO_USE_PLAY; mode!=-1;
418 		mode = (mode == ECHO_USE_PLAY) ? ECHO_USE_RECORD : -1) {
419 		LIST_FOREACH(stream, &((echo_dev*)multi->card)->streams, next) {
420 			if ((stream->use & mode) == 0)
421 				continue;
422 
423 			if(stream->channels == 2)
424 				designations = B_CHANNEL_STEREO_BUS;
425 			else
426 				designations = B_CHANNEL_SURROUND_BUS;
427 
428 			for(i=0; i<stream->channels; i++) {
429 				chans[index].channel_id = index;
430 				chans[index].kind = (mode == ECHO_USE_PLAY) ? B_MULTI_OUTPUT_CHANNEL : B_MULTI_INPUT_CHANNEL;
431 				chans[index].designations = designations | chan_designations[i];
432 				chans[index].connectors = 0;
433 				index++;
434 			}
435 		}
436 
437 		if(mode==ECHO_USE_PLAY) {
438 			multi->output_channel_count = index;
439 		} else {
440 			multi->input_channel_count = index - multi->output_channel_count;
441 		}
442 	}
443 
444 	chans[index].channel_id = index;
445 	chans[index].kind = B_MULTI_OUTPUT_BUS;
446 	chans[index].designations = B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS;
447 	chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
448 	index++;
449 
450 	chans[index].channel_id = index;
451 	chans[index].kind = B_MULTI_OUTPUT_BUS;
452 	chans[index].designations = B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS;
453 	chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
454 	index++;
455 
456 	multi->output_bus_channel_count = index - multi->output_channel_count
457 		- multi->input_channel_count;
458 
459 	chans[index].channel_id = index;
460 	chans[index].kind = B_MULTI_INPUT_BUS;
461 	chans[index].designations = B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS;
462 	chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
463 	index++;
464 
465 	chans[index].channel_id = index;
466 	chans[index].kind = B_MULTI_INPUT_BUS;
467 	chans[index].designations = B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS;
468 	chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
469 	index++;
470 
471 	multi->input_bus_channel_count = index - multi->output_channel_count
472 		- multi->input_channel_count - multi->output_bus_channel_count;
473 
474 	multi->aux_bus_channel_count = 0;
475 }
476 
477 
478 static status_t
479 echo_get_description(echo_dev *card, multi_description *data)
480 {
481 	int32 size;
482 
483 	data->interface_version = B_CURRENT_INTERFACE_VERSION;
484 	data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
485 
486 	strncpy(data->friendly_name, card->caps.szName, 32);
487 	strcpy(data->vendor_info, AUTHOR);
488 
489 	data->output_channel_count = card->multi.output_channel_count;
490 	data->input_channel_count = card->multi.input_channel_count;
491 	data->output_bus_channel_count = card->multi.output_bus_channel_count;
492 	data->input_bus_channel_count = card->multi.input_bus_channel_count;
493 	data->aux_bus_channel_count = card->multi.aux_bus_channel_count;
494 
495 	size = card->multi.output_channel_count + card->multi.input_channel_count
496 			+ card->multi.output_bus_channel_count + card->multi.input_bus_channel_count
497 			+ card->multi.aux_bus_channel_count;
498 
499 	// for each channel, starting with the first output channel,
500 	// then the second, third..., followed by the first input
501 	// channel, second, third, ..., followed by output bus
502 	// channels and input bus channels and finally auxillary channels,
503 
504 	LOG(("request_channel_count = %d\n",data->request_channel_count));
505 	if (data->request_channel_count >= size) {
506 		LOG(("copying data\n"));
507 		memcpy(data->channels, card->multi.chans, size * sizeof(card->multi.chans[0]));
508 	}
509 
510 	switch (current_settings.sample_rate) {
511 		case 192000: data->output_rates = data->input_rates = B_SR_192000; break;
512 		case 96000: data->output_rates = data->input_rates = B_SR_96000; break;
513 		case 48000: data->output_rates = data->input_rates = B_SR_48000; break;
514 		case 44100: data->output_rates = data->input_rates = B_SR_44100; break;
515 	}
516 	data->min_cvsr_rate = 0;
517 	data->max_cvsr_rate = 48000;
518 
519 	switch (current_settings.bitsPerSample) {
520 		case 8: data->output_formats = data->input_formats = B_FMT_8BIT_U; break;
521 		case 16: data->output_formats = data->input_formats = B_FMT_16BIT; break;
522 		case 24: data->output_formats = data->input_formats = B_FMT_24BIT; break;
523 		case 32: data->output_formats = data->input_formats = B_FMT_32BIT; break;
524 	}
525 	data->lock_sources = B_MULTI_LOCK_INTERNAL;
526 	data->timecode_sources = 0;
527 	data->interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
528 	data->start_latency = 3000;
529 
530 	strcpy(data->control_panel,"");
531 
532 	return B_OK;
533 }
534 
535 static status_t
536 echo_get_enabled_channels(echo_dev *card, multi_channel_enable *data)
537 {
538 	B_SET_CHANNEL(data->enable_bits, 0, true);
539 	B_SET_CHANNEL(data->enable_bits, 1, true);
540 	B_SET_CHANNEL(data->enable_bits, 2, true);
541 	B_SET_CHANNEL(data->enable_bits, 3, true);
542 	data->lock_source = B_MULTI_LOCK_INTERNAL;
543 /*
544 	uint32			lock_source;
545 	int32			lock_data;
546 	uint32			timecode_source;
547 	uint32 *		connectors;
548 */
549 	return B_OK;
550 }
551 
552 static status_t
553 echo_set_enabled_channels(echo_dev *card, multi_channel_enable *data)
554 {
555 	PRINT(("set_enabled_channels 0 : %s\n", B_TEST_CHANNEL(data->enable_bits, 0) ? "enabled": "disabled"));
556 	PRINT(("set_enabled_channels 1 : %s\n", B_TEST_CHANNEL(data->enable_bits, 1) ? "enabled": "disabled"));
557 	PRINT(("set_enabled_channels 2 : %s\n", B_TEST_CHANNEL(data->enable_bits, 2) ? "enabled": "disabled"));
558 	PRINT(("set_enabled_channels 3 : %s\n", B_TEST_CHANNEL(data->enable_bits, 3) ? "enabled": "disabled"));
559 	return B_OK;
560 }
561 
562 static status_t
563 echo_get_global_format(echo_dev *card, multi_format_info *data)
564 {
565 	data->output_latency = 0;
566 	data->input_latency = 0;
567 	data->timecode_kind = 0;
568 	switch (current_settings.sample_rate) {
569 		case 192000: data->output.rate = data->input.rate = B_SR_192000; break;
570 		case 96000: data->output.rate = data->input.rate = B_SR_96000; break;
571 		case 48000: data->output.rate = data->input.rate = B_SR_48000; break;
572 		case 44100: data->output.rate = data->input.rate = B_SR_44100; break;
573 	}
574 	switch (current_settings.bitsPerSample) {
575 		case 8: data->input.format = data->output.format = B_FMT_8BIT_U; break;
576 		case 16: data->input.format = data->output.format = B_FMT_16BIT; break;
577 		case 24: data->input.format = data->output.format = B_FMT_24BIT; break;
578 		case 32: data->input.format = data->output.format = B_FMT_32BIT; break;
579 	}
580 	data->input.cvsr = data->output.cvsr = current_settings.sample_rate;
581 	return B_OK;
582 }
583 
584 static status_t
585 echo_get_buffers(echo_dev *card, multi_buffer_list *data)
586 {
587 	int32 i, j, channels;
588 	echo_stream *stream;
589 
590 	LOG(("flags = %#x\n",data->flags));
591 	LOG(("request_playback_buffers = %#x\n",data->request_playback_buffers));
592 	LOG(("request_playback_channels = %#x\n",data->request_playback_channels));
593 	LOG(("request_playback_buffer_size = %#x\n",data->request_playback_buffer_size));
594 	LOG(("request_record_buffers = %#x\n",data->request_record_buffers));
595 	LOG(("request_record_channels = %#x\n",data->request_record_channels));
596 	LOG(("request_record_buffer_size = %#x\n",data->request_record_buffer_size));
597 
598 	if (data->request_playback_buffers < current_settings.buffer_count ||
599 		data->request_record_buffers < current_settings.buffer_count) {
600 		LOG(("not enough channels/buffers\n"));
601 	}
602 
603 	ASSERT(current_settings.buffer_count == 2);
604 
605 	data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD; // XXX ???
606 //	data->flags = 0;
607 
608 	data->return_playback_buffers = current_settings.buffer_count;	/* playback_buffers[b][] */
609 	data->return_playback_channels = 0;	/* playback_buffers[][c] */
610 	data->return_playback_buffer_size = current_settings.buffer_frames;		/* frames */
611 
612 	LIST_FOREACH(stream, &card->streams, next) {
613 		if ((stream->use & ECHO_USE_PLAY) == 0)
614 			continue;
615 		LOG(("get_buffers pipe %d\n", stream->pipe));
616 		channels = data->return_playback_channels;
617 		data->return_playback_channels += stream->channels;
618 		if (data->request_playback_channels < data->return_playback_channels) {
619 			LOG(("not enough channels\n"));
620 		}
621 		for(i=0; i<current_settings.buffer_count; i++)
622 			for(j=0; j<stream->channels; j++)
623 				echo_stream_get_nth_buffer(stream, j, i,
624 					&data->playback_buffers[i][channels+j].base,
625 					&data->playback_buffers[i][channels+j].stride);
626 	}
627 
628 	data->return_record_buffers = current_settings.buffer_count;
629 	data->return_record_channels = 0;
630 	data->return_record_buffer_size = current_settings.buffer_frames;	/* frames */
631 
632 	LIST_FOREACH(stream, &card->streams, next) {
633 		if ((stream->use & ECHO_USE_PLAY) != 0)
634 			continue;
635 		LOG(("get_buffers pipe %d\n", stream->pipe));
636 		channels = data->return_record_channels;
637 		data->return_record_channels += stream->channels;
638 		if (data->request_record_channels < data->return_record_channels) {
639 			LOG(("not enough channels\n"));
640 		}
641 		for(i=0; i<current_settings.buffer_count; i++)
642 			for(j=0; j<stream->channels; j++)
643 				echo_stream_get_nth_buffer(stream, j, i,
644 					&data->record_buffers[i][channels+j].base,
645 					&data->record_buffers[i][channels+j].stride);
646 	}
647 
648 	return B_OK;
649 }
650 
651 
652 void
653 echo_play_inth(void* inthparams)
654 {
655 	echo_stream *stream = (echo_stream *)inthparams;
656 	//int32 count;
657 
658 	//TRACE(("echo_play_inth\n"));
659 
660 	acquire_spinlock(&slock);
661 	stream->real_time = system_time();
662 	stream->frames_count += current_settings.buffer_frames;
663 	stream->buffer_cycle = (stream->trigblk
664 		+ stream->blkmod) % stream->blkmod;
665 	stream->update_needed = true;
666 	release_spinlock(&slock);
667 
668 	//get_sem_count(stream->card->buffer_ready_sem, &count);
669 	//if (count <= 0)
670 		release_sem_etc(stream->card->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
671 }
672 
673 void
674 echo_record_inth(void* inthparams)
675 {
676 	echo_stream *stream = (echo_stream *)inthparams;
677 	//int32 count;
678 
679 	//TRACE(("echo_record_inth\n"));
680 
681 	acquire_spinlock(&slock);
682 	stream->real_time = system_time();
683 	stream->frames_count += current_settings.buffer_frames;
684 	stream->buffer_cycle = (stream->trigblk
685 		+ stream->blkmod - 1) % stream->blkmod;
686 	stream->update_needed = true;
687 	release_spinlock(&slock);
688 
689 	//get_sem_count(stream->card->buffer_ready_sem, &count);
690 	//if (count <= 0)
691 		release_sem_etc(stream->card->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
692 }
693 
694 static status_t
695 echo_buffer_exchange(echo_dev *card, multi_buffer_info *data)
696 {
697 	cpu_status status;
698 	echo_stream *pstream, *rstream, *stream;
699 
700 	data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD;
701 
702 	LIST_FOREACH(stream, &card->streams, next) {
703 		if ((stream->state & ECHO_STATE_STARTED) != 0)
704 			continue;
705 		echo_stream_start(stream,
706 			(stream->use & ECHO_USE_PLAY == 0) ? echo_record_inth : echo_play_inth, stream);
707 	}
708 
709 	if(acquire_sem_etc(card->buffer_ready_sem, 1, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 50000)
710 		== B_TIMED_OUT) {
711 		LOG(("buffer_exchange timeout ff\n"));
712 	}
713 
714 	status = lock();
715 
716 	LIST_FOREACH(pstream, &card->streams, next) {
717 		if ((pstream->use & ECHO_USE_PLAY) == 0 ||
718 			(pstream->state & ECHO_STATE_STARTED) == 0)
719 			continue;
720 		if(pstream->update_needed)
721 			break;
722 	}
723 
724 	LIST_FOREACH(rstream, &card->streams, next) {
725 		if ((rstream->use & ECHO_USE_RECORD) == 0 ||
726 			(rstream->state & ECHO_STATE_STARTED) == 0)
727 			continue;
728 		if(rstream->update_needed)
729 			break;
730 	}
731 
732 	if(!pstream)
733 		pstream = card->pstream;
734 	if(!rstream)
735 		rstream = card->rstream;
736 
737 	/* do playback */
738 	data->playback_buffer_cycle = pstream->buffer_cycle;
739 	data->played_real_time = pstream->real_time;
740 	data->played_frames_count = pstream->frames_count;
741 	data->_reserved_0 = pstream->first_channel;
742 	pstream->update_needed = false;
743 
744 	/* do record */
745 	data->record_buffer_cycle = rstream->buffer_cycle;
746 	data->recorded_frames_count = rstream->frames_count;
747 	data->recorded_real_time = rstream->real_time;
748 	data->_reserved_1 = rstream->first_channel;
749 	rstream->update_needed = false;
750 	unlock(status);
751 
752 	//TRACE(("buffer_exchange ended\n"));
753 	return B_OK;
754 }
755 
756 static status_t
757 echo_buffer_force_stop(echo_dev *card)
758 {
759 	//echo_voice_halt(card->pvoice);
760 	return B_OK;
761 }
762 
763 static status_t
764 echo_multi_control(void *cookie, uint32 op, void *data, size_t length)
765 {
766 	echo_dev *card = (echo_dev *)cookie;
767 
768 #ifdef CARDBUS
769 	// Check
770 	if (card->plugged == false) {
771 		LOG(("device %s unplugged\n", card->name));
772 		return B_ERROR;
773 	}
774 #endif
775 
776     switch (op) {
777 		case B_MULTI_GET_DESCRIPTION:
778 			LOG(("B_MULTI_GET_DESCRIPTION\n"));
779 			return echo_get_description(card, (multi_description *)data);
780 		case B_MULTI_GET_EVENT_INFO:
781 			LOG(("B_MULTI_GET_EVENT_INFO\n"));
782 			return B_ERROR;
783 		case B_MULTI_SET_EVENT_INFO:
784 			LOG(("B_MULTI_SET_EVENT_INFO\n"));
785 			return B_ERROR;
786 		case B_MULTI_GET_EVENT:
787 			LOG(("B_MULTI_GET_EVENT\n"));
788 			return B_ERROR;
789 		case B_MULTI_GET_ENABLED_CHANNELS:
790 			LOG(("B_MULTI_GET_ENABLED_CHANNELS\n"));
791 			return echo_get_enabled_channels(card, (multi_channel_enable *)data);
792 		case B_MULTI_SET_ENABLED_CHANNELS:
793 			LOG(("B_MULTI_SET_ENABLED_CHANNELS\n"));
794 			return echo_set_enabled_channels(card, (multi_channel_enable *)data);
795 		case B_MULTI_GET_GLOBAL_FORMAT:
796 			LOG(("B_MULTI_GET_GLOBAL_FORMAT\n"));
797 			return echo_get_global_format(card, (multi_format_info *)data);
798 		case B_MULTI_SET_GLOBAL_FORMAT:
799 			LOG(("B_MULTI_SET_GLOBAL_FORMAT\n"));
800 			return B_OK; /* XXX BUG! we *MUST* return B_OK, returning B_ERROR will prevent
801 						  * BeOS to accept the format returned in B_MULTI_GET_GLOBAL_FORMAT
802 						  */
803 		case B_MULTI_GET_CHANNEL_FORMATS:
804 			LOG(("B_MULTI_GET_CHANNEL_FORMATS\n"));
805 			return B_ERROR;
806 		case B_MULTI_SET_CHANNEL_FORMATS:	/* only implemented if possible */
807 			LOG(("B_MULTI_SET_CHANNEL_FORMATS\n"));
808 			return B_ERROR;
809 		case B_MULTI_GET_MIX:
810 			LOG(("B_MULTI_GET_MIX\n"));
811 			return echo_get_mix(card, (multi_mix_value_info *)data);
812 		case B_MULTI_SET_MIX:
813 			LOG(("B_MULTI_SET_MIX\n"));
814 			return echo_set_mix(card, (multi_mix_value_info *)data);
815 		case B_MULTI_LIST_MIX_CHANNELS:
816 			LOG(("B_MULTI_LIST_MIX_CHANNELS\n"));
817 			return echo_list_mix_channels(card, (multi_mix_channel_info *)data);
818 		case B_MULTI_LIST_MIX_CONTROLS:
819 			LOG(("B_MULTI_LIST_MIX_CONTROLS\n"));
820 			return echo_list_mix_controls(card, (multi_mix_control_info *)data);
821 		case B_MULTI_LIST_MIX_CONNECTIONS:
822 			LOG(("B_MULTI_LIST_MIX_CONNECTIONS\n"));
823 			return echo_list_mix_connections(card, (multi_mix_connection_info *)data);
824 		case B_MULTI_GET_BUFFERS:			/* Fill out the struct for the first time; doesn't start anything. */
825 			LOG(("B_MULTI_GET_BUFFERS\n"));
826 			return echo_get_buffers(card, (multi_buffer_list*)data);
827 		case B_MULTI_SET_BUFFERS:			/* Set what buffers to use, if the driver supports soft buffers. */
828 			LOG(("B_MULTI_SET_BUFFERS\n"));
829 			return B_ERROR; /* we do not support soft buffers */
830 		case B_MULTI_SET_START_TIME:			/* When to actually start */
831 			LOG(("B_MULTI_SET_START_TIME\n"));
832 			return B_ERROR;
833 		case B_MULTI_BUFFER_EXCHANGE:		/* stop and go are derived from this being called */
834 			//TRACE(("B_MULTI_BUFFER_EXCHANGE\n"));
835 			return echo_buffer_exchange(card, (multi_buffer_info *)data);
836 		case B_MULTI_BUFFER_FORCE_STOP:		/* force stop of playback, nothing in data */
837 			LOG(("B_MULTI_BUFFER_FORCE_STOP\n"));
838 			return echo_buffer_force_stop(card);
839 	}
840 	LOG(("ERROR: unknown multi_control %#x\n",op));
841 	return B_ERROR;
842 }
843 
844 static status_t echo_open(const char *name, uint32 flags, void** cookie);
845 static status_t echo_close(void* cookie);
846 static status_t echo_free(void* cookie);
847 static status_t echo_control(void* cookie, uint32 op, void* arg, size_t len);
848 static status_t echo_read(void* cookie, off_t position, void *buf, size_t* num_bytes);
849 static status_t echo_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes);
850 
851 device_hooks multi_hooks = {
852 	echo_open, 			/* -> open entry point */
853 	echo_close, 			/* -> close entry point */
854 	echo_free,			/* -> free cookie */
855 	echo_control, 		/* -> control entry point */
856 	echo_read,			/* -> read entry point */
857 	echo_write,			/* -> write entry point */
858 	NULL,					/* start select */
859 	NULL,					/* stop select */
860 	NULL,					/* scatter-gather read from the device */
861 	NULL					/* scatter-gather write to the device */
862 };
863 
864 static status_t
865 echo_open(const char *name, uint32 flags, void** cookie)
866 {
867 	echo_dev *card = NULL;
868 	int i, first_record_channel;
869 	echo_stream *stream = NULL;
870 
871 	LOG(("echo_open()\n"));
872 
873 #ifdef CARDBUS
874 	LIST_FOREACH(card, &devices, next) {
875 		if (!strcmp(card->name, name)) {
876 			break;
877 		}
878 	}
879 #else
880 	for (i=0; i<num_cards; i++) {
881 		if (!strcmp(cards[i].name, name)) {
882 			card = &cards[i];
883 		}
884 	}
885 #endif
886 
887 	if(card == NULL) {
888 		LOG(("open() card not found %s\n", name));
889 #ifdef CARDBUS
890 		LIST_FOREACH(card, &devices, next) {
891 			LOG(("open() card available %s\n", card->name));
892 		}
893 #else
894 		for (int ix=0; ix<num_cards; ix++) {
895 			LOG(("open() card available %s\n", cards[ix].name));
896 		}
897 #endif
898 		return B_ERROR;
899 	}
900 
901 #ifdef CARDBUS
902 	if (card->plugged == false) {
903 		LOG(("device %s unplugged\n", name));
904 		return B_ERROR;
905 	}
906 #endif
907 
908 	LOG(("open() got card\n"));
909 
910 	if (card->pstream != NULL)
911 		return B_ERROR;
912 	if (card->rstream != NULL)
913 		return B_ERROR;
914 
915 	*cookie = card;
916 	card->multi.card = card;
917 #ifdef CARDBUS
918 	card->opened = true;
919 #endif
920 
921 	LOG(("creating play streams\n"));
922 
923 	i = card->caps.wNumPipesOut - 2;
924 	first_record_channel = card->caps.wNumPipesOut;
925 #ifdef ECHO3G_FAMILY
926 	if (current_settings.sample_rate > 50000) {
927 		i = card->caps.wFirstDigitalBusOut;
928 		first_record_channel = card->caps.wFirstDigitalBusOut + 2;
929 	}
930 #endif
931 
932 	for (; i >=0 ; i-=2) {
933 		stream = echo_stream_new(card, ECHO_USE_PLAY, current_settings.buffer_frames, current_settings.buffer_count);
934 		if (!card->pstream)
935 			card->pstream = stream;
936 		echo_stream_set_audioparms(stream, current_settings.channels,
937 			current_settings.bitsPerSample, current_settings.sample_rate, i);
938 		stream->first_channel = i;
939 	}
940 
941 	LOG(("creating record streams\n"));
942 	i = card->caps.wNumPipesIn - 2;
943 #ifdef ECHO3G_FAMILY
944 	if (current_settings.sample_rate > 50000) {
945 		i = card->caps.wFirstDigitalBusIn;
946 	}
947 #endif
948 
949 	for (; i >= 0; i-=2) {
950 		stream = echo_stream_new(card, ECHO_USE_RECORD, current_settings.buffer_frames, current_settings.buffer_count);
951 		if (!card->rstream)
952 			card->rstream = stream;
953 		echo_stream_set_audioparms(stream, current_settings.channels,
954 			current_settings.bitsPerSample, current_settings.sample_rate, i);
955 		stream->first_channel = i + first_record_channel;
956 	}
957 
958 	card->buffer_ready_sem = create_sem(0, "pbuffer ready");
959 
960 	LOG(("creating channels list\n"));
961 	echo_create_channels_list(&card->multi);
962 
963 	return B_OK;
964 }
965 
966 static status_t
967 echo_close(void* cookie)
968 {
969 	LOG(("close()\n"));
970 #ifdef CARDBUS
971 	echo_dev *card = (echo_dev *) cookie;
972 	card->opened = false;
973 #endif
974 
975 	return B_OK;
976 }
977 
978 static status_t
979 echo_free(void* cookie)
980 {
981 	echo_dev *card = (echo_dev *) cookie;
982 	echo_stream *stream;
983 	LOG(("echo_free()\n"));
984 
985 	if (card->buffer_ready_sem > B_OK)
986 			delete_sem(card->buffer_ready_sem);
987 
988 	LIST_FOREACH(stream, &card->streams, next) {
989 		echo_stream_halt(stream);
990 	}
991 
992 	while(!LIST_EMPTY(&card->streams)) {
993 		echo_stream_delete(LIST_FIRST(&card->streams));
994 	}
995 
996 	card->pstream = NULL;
997 	card->rstream = NULL;
998 
999 	return B_OK;
1000 }
1001 
1002 static status_t
1003 echo_control(void* cookie, uint32 op, void* arg, size_t len)
1004 {
1005 	return echo_multi_control(cookie, op, arg, len);
1006 }
1007 
1008 static status_t
1009 echo_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
1010 {
1011 	*num_bytes = 0;				/* tell caller nothing was read */
1012 	return B_IO_ERROR;
1013 }
1014 
1015 static status_t
1016 echo_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
1017 {
1018 	*num_bytes = 0;				/* tell caller nothing was written */
1019 	return B_IO_ERROR;
1020 }
1021 
1022