1/*
2 * Auich BeOS Driver for Intel Southbridge audio
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 <driver_settings.h>
33#include <OS.h>
34#include <MediaDefs.h>
35#include <string.h>
36#include <strings.h>
37
38#include <kernel.h>
39
40#include "hmulti_audio.h"
41#include "multi.h"
42#include "ac97.h"
43
44//#define DEBUG 1
45
46#include "debug.h"
47#include "auich.h"
48#include "util.h"
49#include "io.h"
50
51
52static void
53auich_ac97_get_mix(void *card, const void *cookie, int32 type, float *values) {
54	auich_dev *dev = (auich_dev*)card;
55	ac97_source_info *info = (ac97_source_info *)cookie;
56	uint16 value, mask;
57	float gain;
58
59	switch(type) {
60		case B_MIX_GAIN:
61			value = auich_codec_read(&dev->config, info->reg);
62			//PRINT(("B_MIX_GAIN value : %u\n", value));
63			if (info->type & B_MIX_STEREO) {
64				mask = ((1 << (info->bits + 1)) - 1) << 8;
65				gain = ((value & mask) >> 8) * info->granularity;
66				if (info->polarity == 1)
67					values[0] = info->max_gain - gain;
68				else
69					values[0] = gain - info->min_gain;
70
71				mask = ((1 << (info->bits + 1)) - 1);
72				gain = (value & mask) * info->granularity;
73				if (info->polarity == 1)
74					values[1] = info->max_gain - gain;
75				else
76					values[1] = gain - info->min_gain;
77			} else {
78				mask = ((1 << (info->bits + 1)) - 1);
79				gain = (value & mask) * info->granularity;
80				if (info->polarity == 1)
81					values[0] = info->max_gain - gain;
82				else
83					values[0] = gain - info->min_gain;
84			}
85			break;
86		case B_MIX_MUTE:
87			mask = ((1 << 1) - 1) << 15;
88			value = auich_codec_read(&dev->config, info->reg);
89			//PRINT(("B_MIX_MUTE value : %u\n", value));
90			value &= mask;
91			values[0] = ((value >> 15) == 1) ? 1.0 : 0.0;
92			break;
93		case B_MIX_MICBOOST:
94			mask = ((1 << 1) - 1) << 6;
95			value = auich_codec_read(&dev->config, info->reg);
96			//PRINT(("B_MIX_MICBOOST value : %u\n", value));
97			value &= mask;
98			values[0] = ((value >> 6) == 1) ? 1.0 : 0.0;
99			break;
100		case B_MIX_MUX:
101			mask = ((1 << 3) - 1);
102			value = auich_codec_read(&dev->config, AC97_RECORD_SELECT);
103			value &= mask;
104			//PRINT(("B_MIX_MUX value : %u\n", value));
105			values[0] = (float)value;
106			break;
107	}
108}
109
110
111static void
112auich_ac97_set_mix(void *card, const void *cookie, int32 type, float *values) {
113	auich_dev *dev = (auich_dev*)card;
114	ac97_source_info *info = (ac97_source_info *)cookie;
115	uint16 value, mask;
116	float gain;
117
118	switch(type) {
119		case B_MIX_GAIN:
120			value = auich_codec_read(&dev->config, info->reg);
121			if (info->type & B_MIX_STEREO) {
122				mask = ((1 << (info->bits + 1)) - 1) << 8;
123				value &= ~mask;
124
125				if (info->polarity == 1)
126					gain = info->max_gain - values[0];
127				else
128					gain =  values[0] - info->min_gain;
129				value |= ((uint16)(gain	/ info->granularity) << 8) & mask;
130
131				mask = ((1 << (info->bits + 1)) - 1);
132				value &= ~mask;
133				if (info->polarity == 1)
134					gain = info->max_gain - values[1];
135				else
136					gain =  values[1] - info->min_gain;
137				value |= ((uint16)(gain / info->granularity)) & mask;
138			} else {
139				mask = ((1 << (info->bits + 1)) - 1);
140				value &= ~mask;
141				if (info->polarity == 1)
142					gain = info->max_gain - values[0];
143				else
144					gain =  values[0] - info->min_gain;
145				value |= ((uint16)(gain / info->granularity)) & mask;
146			}
147			//PRINT(("B_MIX_GAIN value : %u\n", value));
148			auich_codec_write(&dev->config, info->reg, value);
149			break;
150		case B_MIX_MUTE:
151			mask = ((1 << 1) - 1) << 15;
152			value = auich_codec_read(&dev->config, info->reg);
153			value &= ~mask;
154			value |= ((values[0] == 1.0 ? 1 : 0 ) << 15 & mask);
155			if (info->reg == AC97_SURR_VOLUME) {
156				// there is a independent mute for each channel
157				mask = ((1 << 1) - 1) << 7;
158				value &= ~mask;
159				value |= ((values[0] == 1.0 ? 1 : 0 ) << 7 & mask);
160			}
161			//PRINT(("B_MIX_MUTE value : %u\n", value));
162			auich_codec_write(&dev->config, info->reg, value);
163			break;
164		case B_MIX_MICBOOST:
165			mask = ((1 << 1) - 1) << 6;
166			value = auich_codec_read(&dev->config, info->reg);
167			value &= ~mask;
168			value |= ((values[0] == 1.0 ? 1 : 0 ) << 6 & mask);
169			//PRINT(("B_MIX_MICBOOST value : %u\n", value));
170			auich_codec_write(&dev->config, info->reg, value);
171			break;
172		case B_MIX_MUX:
173			mask = ((1 << 3) - 1);
174			value = ((int32)values[0]) & mask;
175			value = value | (value << 8);
176			//PRINT(("B_MIX_MUX value : %u\n", value));
177			auich_codec_write(&dev->config, AC97_RECORD_SELECT, value);
178			break;
179	}
180
181}
182
183
184static int32
185auich_create_group_control(multi_dev *multi, uint32 *index, int32 parent, int32 string,
186	const char* name)
187{
188	uint32 i = *index;
189	(*index)++;
190	multi->controls[i].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + i;
191	multi->controls[i].mix_control.parent = parent;
192	multi->controls[i].mix_control.flags = B_MULTI_MIX_GROUP;
193	multi->controls[i].mix_control.master = EMU_MULTI_CONTROL_MASTERID;
194	multi->controls[i].mix_control.string = string;
195	if (name)
196		strcpy(multi->controls[i].mix_control.name, name);
197
198	return multi->controls[i].mix_control.id;
199}
200
201
202static status_t
203auich_create_controls_list(multi_dev *multi)
204{
205	uint32 i = 0, index = 0, count, id, parent, parent2, parent3;
206	const ac97_source_info *info;
207
208	/* AC97 Mixer */
209	parent = auich_create_group_control(multi, &index, 0, 0, "AC97 mixer");
210
211	count = source_info_size;
212	//Note that we ignore first item in source_info
213	//It's for recording, but do match this with ac97.c's source_info
214	for (i = 1; i < count ; i++) {
215		info = &source_info[i];
216		PRINT(("name : %s\n", info->name));
217
218		parent2 = auich_create_group_control(multi, &index, parent, 0, info->name);
219
220		if (info->type & B_MIX_GAIN) {
221			if (info->type & B_MIX_MUTE) {
222				multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
223				multi->controls[index].mix_control.flags = B_MULTI_MIX_ENABLE;
224				multi->controls[index].mix_control.master = EMU_MULTI_CONTROL_MASTERID;
225				multi->controls[index].mix_control.parent = parent2;
226				multi->controls[index].mix_control.string = S_MUTE;
227				multi->controls[index].cookie = info;
228				multi->controls[index].type = B_MIX_MUTE;
229				multi->controls[index].get = &auich_ac97_get_mix;
230				multi->controls[index].set = &auich_ac97_set_mix;
231				index++;
232			}
233
234			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
235			multi->controls[index].mix_control.flags = B_MULTI_MIX_GAIN;
236			multi->controls[index].mix_control.master = EMU_MULTI_CONTROL_MASTERID;
237			multi->controls[index].mix_control.parent = parent2;
238			strcpy(multi->controls[index].mix_control.name, info->name);
239			multi->controls[index].mix_control.u.gain.min_gain = info->min_gain;
240			multi->controls[index].mix_control.u.gain.max_gain = info->max_gain;
241			multi->controls[index].mix_control.u.gain.granularity = info->granularity;
242			multi->controls[index].cookie = info;
243			multi->controls[index].type = B_MIX_GAIN;
244			multi->controls[index].get = &auich_ac97_get_mix;
245			multi->controls[index].set = &auich_ac97_set_mix;
246			id = multi->controls[index].mix_control.id;
247			index++;
248
249			if (info->type & B_MIX_STEREO) {
250				multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
251				multi->controls[index].mix_control.flags = B_MULTI_MIX_GAIN;
252				multi->controls[index].mix_control.master = id;
253				multi->controls[index].mix_control.parent = parent2;
254				strcpy(multi->controls[index].mix_control.name, info->name);
255				multi->controls[index].mix_control.u.gain.min_gain = info->min_gain;
256				multi->controls[index].mix_control.u.gain.max_gain = info->max_gain;
257				multi->controls[index].mix_control.u.gain.granularity = info->granularity;
258				multi->controls[index].cookie = info;
259				multi->controls[index].type = B_MIX_GAIN;
260				multi->controls[index].get = &auich_ac97_get_mix;
261				multi->controls[index].set = &auich_ac97_set_mix;
262				index++;
263			}
264
265			if (info->type & B_MIX_MICBOOST) {
266				multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
267				multi->controls[index].mix_control.flags = B_MULTI_MIX_ENABLE;
268				multi->controls[index].mix_control.master = EMU_MULTI_CONTROL_MASTERID;
269				multi->controls[index].mix_control.parent = parent2;
270				strcpy(multi->controls[index].mix_control.name, "+20 dB");
271				multi->controls[index].cookie = info;
272				multi->controls[index].type = B_MIX_MICBOOST;
273				multi->controls[index].get = &auich_ac97_get_mix;
274				multi->controls[index].set = &auich_ac97_set_mix;
275				index++;
276			}
277		}
278	}
279
280	/* AC97 Record */
281	parent = auich_create_group_control(multi, &index, 0, 0, "Recording");
282
283	info = &source_info[0];
284	PRINT(("name : %s\n", info->name));
285
286	parent2 = auich_create_group_control(multi, &index, parent, 0, info->name);
287
288	if (info->type & B_MIX_GAIN) {
289		if (info->type & B_MIX_MUTE) {
290			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
291			multi->controls[index].mix_control.flags = B_MULTI_MIX_ENABLE;
292			multi->controls[index].mix_control.master = EMU_MULTI_CONTROL_MASTERID;
293			multi->controls[index].mix_control.parent = parent2;
294			multi->controls[index].mix_control.string = S_MUTE;
295			multi->controls[index].cookie = info;
296			multi->controls[index].type = B_MIX_MUTE;
297			multi->controls[index].get = &auich_ac97_get_mix;
298			multi->controls[index].set = &auich_ac97_set_mix;
299			index++;
300		}
301
302		multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
303		multi->controls[index].mix_control.flags = B_MULTI_MIX_GAIN;
304		multi->controls[index].mix_control.master = EMU_MULTI_CONTROL_MASTERID;
305		multi->controls[index].mix_control.parent = parent2;
306		strcpy(multi->controls[index].mix_control.name, info->name);
307		multi->controls[index].mix_control.u.gain.min_gain = info->min_gain;
308		multi->controls[index].mix_control.u.gain.max_gain = info->max_gain;
309		multi->controls[index].mix_control.u.gain.granularity = info->granularity;
310		multi->controls[index].cookie = info;
311		multi->controls[index].type = B_MIX_GAIN;
312		multi->controls[index].get = &auich_ac97_get_mix;
313		multi->controls[index].set = &auich_ac97_set_mix;
314		id = multi->controls[index].mix_control.id;
315		index++;
316
317		if (info->type & B_MIX_STEREO) {
318			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
319			multi->controls[index].mix_control.flags = B_MULTI_MIX_GAIN;
320			multi->controls[index].mix_control.master = id;
321			multi->controls[index].mix_control.parent = parent2;
322			strcpy(multi->controls[index].mix_control.name, info->name);
323			multi->controls[index].mix_control.u.gain.min_gain = info->min_gain;
324			multi->controls[index].mix_control.u.gain.max_gain = info->max_gain;
325			multi->controls[index].mix_control.u.gain.granularity = info->granularity;
326			multi->controls[index].cookie = info;
327			multi->controls[index].type = B_MIX_GAIN;
328			multi->controls[index].get = &auich_ac97_get_mix;
329			multi->controls[index].set = &auich_ac97_set_mix;
330			index++;
331		}
332
333		if (info->type & B_MIX_RECORDMUX) {
334			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
335			multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX;
336			multi->controls[index].mix_control.parent = parent2;
337			strcpy(multi->controls[index].mix_control.name, "Record mux");
338			multi->controls[index].cookie = info;
339			multi->controls[index].type = B_MIX_MUX;
340			multi->controls[index].get = &auich_ac97_get_mix;
341			multi->controls[index].set = &auich_ac97_set_mix;
342			parent3 = multi->controls[index].mix_control.id;
343			index++;
344
345			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
346			multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
347			multi->controls[index].mix_control.parent = parent3;
348			multi->controls[index].mix_control.string = S_MIC;
349			index++;
350			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
351			multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
352			multi->controls[index].mix_control.parent = parent3;
353			strcpy(multi->controls[index].mix_control.name, "CD in");
354			index++;
355			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
356			multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
357			multi->controls[index].mix_control.parent = parent3;
358			strcpy(multi->controls[index].mix_control.name, "Video in");
359			index++;
360			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
361			multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
362			multi->controls[index].mix_control.parent = parent3;
363			strcpy(multi->controls[index].mix_control.name, "Aux in");
364			index++;
365			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
366			multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
367			multi->controls[index].mix_control.parent = parent3;
368			strcpy(multi->controls[index].mix_control.name, "Line in");
369			index++;
370			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
371			multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
372			multi->controls[index].mix_control.parent = parent3;
373			multi->controls[index].mix_control.string = S_STEREO_MIX;
374			index++;
375			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
376			multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
377			multi->controls[index].mix_control.parent = parent3;
378			multi->controls[index].mix_control.string = S_MONO_MIX;
379			index++;
380			multi->controls[index].mix_control.id = EMU_MULTI_CONTROL_FIRSTID + index;
381			multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
382			multi->controls[index].mix_control.parent = parent3;
383			strcpy(multi->controls[index].mix_control.name, "TAD");
384			index++;
385		}
386	}
387
388	multi->control_count = index;
389	PRINT(("multi->control_count %" B_PRIu32 "\n", multi->control_count));
390	return B_OK;
391}
392
393
394static status_t
395auich_get_mix(auich_dev *card, multi_mix_value_info * mmvi)
396{
397	int32 i, id;
398	multi_mixer_control *control = NULL;
399	for (i = 0; i < mmvi->item_count; i++) {
400		id = mmvi->values[i].id - EMU_MULTI_CONTROL_FIRSTID;
401		if (id < 0 || (uint32)id >= card->multi.control_count) {
402			PRINT(("auich_get_mix : "
403				"invalid control id requested : %" B_PRIi32 "\n", id));
404			continue;
405		}
406		control = &card->multi.controls[id];
407
408		if (control->mix_control.flags & B_MULTI_MIX_GAIN) {
409			if (control->get) {
410				float values[2];
411				control->get(card, control->cookie, control->type, values);
412				if (control->mix_control.master == EMU_MULTI_CONTROL_MASTERID)
413					mmvi->values[i].u.gain = values[0];
414				else
415					mmvi->values[i].u.gain = values[1];
416			}
417		}
418
419		if (control->mix_control.flags & B_MULTI_MIX_ENABLE && control->get) {
420			float values[1];
421			control->get(card, control->cookie, control->type, values);
422			mmvi->values[i].u.enable = (values[0] == 1.0);
423		}
424
425		if (control->mix_control.flags & B_MULTI_MIX_MUX && control->get) {
426			float values[1];
427			control->get(card, control->cookie, control->type, values);
428			mmvi->values[i].u.mux = (int32)values[0];
429		}
430	}
431	return B_OK;
432}
433
434
435static status_t
436auich_set_mix(auich_dev *card, multi_mix_value_info * mmvi)
437{
438	int32 i, id;
439	multi_mixer_control *control = NULL;
440	for (i = 0; i < mmvi->item_count; i++) {
441		id = mmvi->values[i].id - EMU_MULTI_CONTROL_FIRSTID;
442		if (id < 0 || (uint32)id >= card->multi.control_count) {
443			PRINT(("auich_set_mix : "
444				"invalid control id requested : %" B_PRIi32 "\n", id));
445			continue;
446		}
447		control = &card->multi.controls[id];
448
449		if (control->mix_control.flags & B_MULTI_MIX_GAIN) {
450			multi_mixer_control *control2 = NULL;
451			if (i+1<mmvi->item_count) {
452				id = mmvi->values[i + 1].id - EMU_MULTI_CONTROL_FIRSTID;
453				if (id < 0 || (uint32)id >= card->multi.control_count) {
454					PRINT(("auich_set_mix : "
455						"invalid control id requested : %" B_PRIi32 "\n", id));
456				} else {
457					control2 = &card->multi.controls[id];
458					if (control2->mix_control.master != control->mix_control.id)
459						control2 = NULL;
460				}
461			}
462
463			if (control->set) {
464				float values[2];
465				values[0] = 0.0;
466				values[1] = 0.0;
467
468				if (control->mix_control.master == EMU_MULTI_CONTROL_MASTERID)
469					values[0] = mmvi->values[i].u.gain;
470				else
471					values[1] = mmvi->values[i].u.gain;
472
473				if (control2 && control2->mix_control.master != EMU_MULTI_CONTROL_MASTERID)
474					values[1] = mmvi->values[i+1].u.gain;
475
476				control->set(card, control->cookie, control->type, values);
477			}
478
479			if (control2)
480				i++;
481		}
482
483		if (control->mix_control.flags & B_MULTI_MIX_ENABLE && control->set) {
484			float values[1];
485
486			values[0] = mmvi->values[i].u.enable ? 1.0 : 0.0;
487			control->set(card, control->cookie, control->type, values);
488		}
489
490		if (control->mix_control.flags & B_MULTI_MIX_MUX && control->set) {
491			float values[1];
492
493			values[0] = (float)mmvi->values[i].u.mux;
494			control->set(card, control->cookie, control->type, values);
495		}
496	}
497	return B_OK;
498}
499
500
501static status_t
502auich_list_mix_controls(auich_dev *card, multi_mix_control_info * mmci)
503{
504	multi_mix_control	*mmc;
505	uint32 i;
506
507	mmc = mmci->controls;
508	if (mmci->control_count < 24)
509		return B_ERROR;
510
511	if (auich_create_controls_list(&card->multi) < B_OK)
512		return B_ERROR;
513
514	for (i = 0; i < card->multi.control_count; i++)
515		mmc[i] = card->multi.controls[i].mix_control;
516
517	mmci->control_count = card->multi.control_count;
518	return B_OK;
519}
520
521
522static status_t
523auich_list_mix_connections(auich_dev *card, multi_mix_connection_info * data)
524{
525	return B_ERROR;
526}
527
528
529static status_t
530auich_list_mix_channels(auich_dev *card, multi_mix_channel_info *data)
531{
532	return B_ERROR;
533}
534
535/*multi_channel_info chans[] = {
536{  0, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
537{  1, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
538{  2, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
539{  3, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
540{  4, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
541{  5, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
542{  6, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
543{  7, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
544{  8, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
545{  9, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
546{  10, B_MULTI_INPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
547{  11, B_MULTI_INPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
548};*/
549
550/*multi_channel_info chans[] = {
551{  0, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
552{  1, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
553{  2, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_SURROUND_BUS, 0 },
554{  3, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_SURROUND_BUS, 0 },
555{  4, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_REARLEFT | B_CHANNEL_SURROUND_BUS, 0 },
556{  5, B_MULTI_OUTPUT_CHANNEL, 	B_CHANNEL_REARRIGHT | B_CHANNEL_SURROUND_BUS, 0 },
557{  6, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
558{  7, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
559{  8, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
560{  9, B_MULTI_INPUT_CHANNEL, 	B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
561{  10, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
562{  11, B_MULTI_OUTPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
563{  12, B_MULTI_INPUT_BUS, 		B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 	B_CHANNEL_MINI_JACK_STEREO },
564{  13, B_MULTI_INPUT_BUS, 		B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, B_CHANNEL_MINI_JACK_STEREO },
565};*/
566
567
568static void
569auich_create_channels_list(multi_dev *multi)
570{
571	auich_stream *stream;
572	uint32 index, i, mode, designations;
573	multi_channel_info *chans;
574	uint32 chan_designations[] = {
575		B_CHANNEL_LEFT,
576		B_CHANNEL_RIGHT,
577		B_CHANNEL_REARLEFT,
578		B_CHANNEL_REARRIGHT,
579		B_CHANNEL_CENTER,
580		B_CHANNEL_SUB
581	};
582
583	chans = multi->chans;
584	index = 0;
585
586	for (mode = AUICH_USE_PLAY; (int32)mode != -1;
587		mode = (mode == AUICH_USE_PLAY) ? AUICH_USE_RECORD : -1) {
588		LIST_FOREACH(stream, &((auich_dev*)multi->card)->streams, next) {
589			if ((stream->use & mode) == 0)
590				continue;
591
592			if (stream->channels == 2)
593				designations = B_CHANNEL_STEREO_BUS;
594			else
595				designations = B_CHANNEL_SURROUND_BUS;
596
597			for (i = 0; i < stream->channels; i++) {
598				chans[index].channel_id = index;
599				chans[index].kind
600					= (mode == AUICH_USE_PLAY) ? B_MULTI_OUTPUT_CHANNEL : B_MULTI_INPUT_CHANNEL;
601				chans[index].designations = designations | chan_designations[i];
602				chans[index].connectors = 0;
603				index++;
604			}
605		}
606
607		if (mode == AUICH_USE_PLAY)
608			multi->output_channel_count = index;
609		else
610			multi->input_channel_count = index - multi->output_channel_count;
611	}
612
613	chans[index].channel_id = index;
614	chans[index].kind = B_MULTI_OUTPUT_BUS;
615	chans[index].designations = B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS;
616	chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
617	index++;
618
619	chans[index].channel_id = index;
620	chans[index].kind = B_MULTI_OUTPUT_BUS;
621	chans[index].designations = B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS;
622	chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
623	index++;
624
625	multi->output_bus_channel_count = index - multi->output_channel_count
626		- multi->input_channel_count;
627
628	chans[index].channel_id = index;
629	chans[index].kind = B_MULTI_INPUT_BUS;
630	chans[index].designations = B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS;
631	chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
632	index++;
633
634	chans[index].channel_id = index;
635	chans[index].kind = B_MULTI_INPUT_BUS;
636	chans[index].designations = B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS;
637	chans[index].connectors = B_CHANNEL_MINI_JACK_STEREO;
638	index++;
639
640	multi->input_bus_channel_count = index - multi->output_channel_count
641		- multi->input_channel_count - multi->output_bus_channel_count;
642
643	multi->aux_bus_channel_count = 0;
644}
645
646
647static status_t
648auich_get_description(auich_dev *card, multi_description *data)
649{
650	uint32 size;
651
652	data->interface_version = B_CURRENT_INTERFACE_VERSION;
653	data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
654
655	switch(card->info.vendor_id) {
656		case INTEL_VENDOR_ID:
657			strncpy(data->friendly_name, FRIENDLY_NAME_ICH, 32);
658		break;
659		case SIS_VENDOR_ID:
660			strncpy(data->friendly_name, FRIENDLY_NAME_SIS, 32);
661		break;
662		case NVIDIA_VENDOR_ID:
663			strncpy(data->friendly_name, FRIENDLY_NAME_NVIDIA, 32);
664		break;
665		case AMD_VENDOR_ID:
666			strncpy(data->friendly_name, FRIENDLY_NAME_AMD, 32);
667		break;
668	}
669
670	strcpy(data->vendor_info, AUTHOR);
671
672	/*data->output_channel_count = 6;
673	data->input_channel_count = 4;
674	data->output_bus_channel_count = 2;
675	data->input_bus_channel_count = 2;
676	data->aux_bus_channel_count = 0;*/
677
678	data->output_channel_count = card->multi.output_channel_count;
679	data->input_channel_count = card->multi.input_channel_count;
680	data->output_bus_channel_count = card->multi.output_bus_channel_count;
681	data->input_bus_channel_count = card->multi.input_bus_channel_count;
682	data->aux_bus_channel_count = card->multi.aux_bus_channel_count;
683
684	size = card->multi.output_channel_count + card->multi.input_channel_count
685			+ card->multi.output_bus_channel_count + card->multi.input_bus_channel_count
686			+ card->multi.aux_bus_channel_count;
687
688	// for each channel, starting with the first output channel,
689	// then the second, third..., followed by the first input
690	// channel, second, third, ..., followed by output bus
691	// channels and input bus channels and finally auxillary channels,
692
693	LOG(("request_channel_count = %d\n",data->request_channel_count));
694	if (data->request_channel_count >= (int32)size) {
695		LOG(("copying data\n"));
696		memcpy(data->channels, card->multi.chans, size * sizeof(card->multi.chans[0]));
697	}
698
699	switch (current_settings.sample_rate) {
700		case 48000: data->output_rates = data->input_rates = B_SR_48000; break;
701		case 44100: data->output_rates = data->input_rates = B_SR_44100; break;
702	}
703	data->min_cvsr_rate = 0;
704	data->max_cvsr_rate = 48000;
705
706	data->output_formats = B_FMT_16BIT;
707	data->input_formats = B_FMT_16BIT;
708	data->lock_sources = B_MULTI_LOCK_INTERNAL;
709	data->timecode_sources = 0;
710	data->interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
711	data->start_latency = 3000;
712
713	strcpy(data->control_panel,"");
714
715	return B_OK;
716}
717
718
719static status_t
720auich_get_enabled_channels(auich_dev *card, multi_channel_enable *data)
721{
722	B_SET_CHANNEL(data->enable_bits, 0, true);
723	B_SET_CHANNEL(data->enable_bits, 1, true);
724	B_SET_CHANNEL(data->enable_bits, 2, true);
725	B_SET_CHANNEL(data->enable_bits, 3, true);
726	data->lock_source = B_MULTI_LOCK_INTERNAL;
727/*
728	uint32			lock_source;
729	int32			lock_data;
730	uint32			timecode_source;
731	uint32 *		connectors;
732*/
733	return B_OK;
734}
735
736
737static status_t
738auich_get_global_format(auich_dev *card, multi_format_info *data)
739{
740	data->output_latency = 0;
741	data->input_latency = 0;
742	data->timecode_kind = 0;
743	switch (current_settings.sample_rate) {
744		case 48000:
745			data->input.rate = data->output.rate = B_SR_48000;
746			data->input.cvsr = data->output.cvsr = 48000;
747			break;
748		case 44100:
749			data->input.rate = data->output.rate = B_SR_44100;
750			data->input.cvsr = data->output.cvsr = 44100;
751			break;
752	}
753	data->input.format = data->output.format = B_FMT_16BIT;
754	return B_OK;
755}
756
757
758static status_t
759auich_set_global_format(auich_dev *card, multi_format_info* data)
760{
761	// TODO: it looks like we're not supposed to fail; fix this!
762	return B_OK;
763}
764
765
766static status_t
767auich_get_buffers(auich_dev *card, multi_buffer_list *data)
768{
769	uint8 i, j, pchannels, rchannels, bufcount;
770
771	LOG(("flags = %#x\n",data->flags));
772	LOG(("request_playback_buffers = %#x\n",data->request_playback_buffers));
773	LOG(("request_playback_channels = %#x\n",data->request_playback_channels));
774	LOG(("request_playback_buffer_size = %#x\n",data->request_playback_buffer_size));
775	LOG(("request_record_buffers = %#x\n",data->request_record_buffers));
776	LOG(("request_record_channels = %#x\n",data->request_record_channels));
777	LOG(("request_record_buffer_size = %#x\n",data->request_record_buffer_size));
778
779	pchannels = card->pstream->channels;
780	rchannels = card->rstream->channels;
781
782	if (data->request_playback_buffers < current_settings.buffer_count ||
783		data->request_playback_channels < (pchannels) ||
784		data->request_record_buffers < current_settings.buffer_count ||
785		data->request_record_channels < (rchannels)) {
786		LOG(("not enough channels/buffers\n"));
787	}
788
789	ASSERT(current_settings.buffer_count == 2);
790
791	data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD; // XXX ???
792//	data->flags = 0;
793
794	data->return_playback_buffers = current_settings.buffer_count;	/* playback_buffers[b][] */
795	data->return_playback_channels = pchannels;		/* playback_buffers[][c] */
796	data->return_playback_buffer_size = current_settings.buffer_frames;		/* frames */
797
798	bufcount = current_settings.buffer_count;
799	if (bufcount > data->request_playback_buffers)
800		bufcount = data->request_playback_buffers;
801
802	for (i = 0; i < bufcount; i++) {
803		struct buffer_desc descs[data->return_playback_channels];
804		for (j=0; j<pchannels; j++)
805			auich_stream_get_nth_buffer(card->pstream, j, i,
806				&descs[j].base,
807				&descs[j].stride);
808		if (!IS_USER_ADDRESS(data->playback_buffers[i])
809			|| user_memcpy(data->playback_buffers[i], descs, sizeof(descs))
810			< B_OK) {
811			return B_BAD_ADDRESS;
812		}
813	}
814	data->return_record_buffers = current_settings.buffer_count;
815	data->return_record_channels = rchannels;
816	data->return_record_buffer_size = current_settings.buffer_frames;	/* frames */
817
818	bufcount = current_settings.buffer_count;
819	if (bufcount > data->request_record_buffers)
820		bufcount = data->request_record_buffers;
821
822	for (i = 0; i < bufcount; i++) {
823		struct buffer_desc descs[data->return_record_channels];
824		for (j=0; j<rchannels; j++)
825			auich_stream_get_nth_buffer(card->rstream, j, i,
826				&descs[j].base,
827				&descs[j].stride);
828		if (!IS_USER_ADDRESS(data->record_buffers[i])
829			|| user_memcpy(data->record_buffers[i], descs, sizeof(descs))
830			< B_OK) {
831			return B_BAD_ADDRESS;
832		}
833	}
834	return B_OK;
835}
836
837
838static void
839auich_play_inth(void* inthparams)
840{
841	auich_stream *stream = (auich_stream *)inthparams;
842	//int32 count;
843
844	acquire_spinlock(&slock);
845	stream->real_time = system_time();
846	stream->frames_count += current_settings.buffer_frames;
847	stream->buffer_cycle = (stream->trigblk
848		+ stream->blkmod - 1) % stream->blkmod;
849	stream->update_needed = true;
850	release_spinlock(&slock);
851
852	TRACE(("auich_play_inth : cycle : %d\n", stream->buffer_cycle));
853
854	//get_sem_count(stream->card->buffer_ready_sem, &count);
855	//if (count <= 0)
856		release_sem_etc(stream->card->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
857}
858
859
860static void
861auich_record_inth(void* inthparams)
862{
863	auich_stream *stream = (auich_stream *)inthparams;
864	//int32 count;
865
866	acquire_spinlock(&slock);
867	stream->real_time = system_time();
868	stream->frames_count += current_settings.buffer_frames;
869	stream->buffer_cycle = (stream->trigblk
870		+ stream->blkmod - 1) % stream->blkmod;
871	stream->update_needed = true;
872	release_spinlock(&slock);
873
874	TRACE(("auich_record_inth : cycle : %d\n", stream->buffer_cycle));
875
876	//get_sem_count(stream->card->buffer_ready_sem, &count);
877	//if (count <= 0)
878		release_sem_etc(stream->card->buffer_ready_sem, 1, B_DO_NOT_RESCHEDULE);
879}
880
881
882static status_t
883auich_buffer_exchange(auich_dev *card, multi_buffer_info *data)
884{
885	cpu_status status;
886	auich_stream *pstream, *rstream;
887	multi_buffer_info buffer_info;
888
889#ifdef __HAIKU__
890	if (user_memcpy(&buffer_info, data, sizeof(buffer_info)) < B_OK)
891		return B_BAD_ADDRESS;
892#else
893	memcpy(&buffer_info, data, sizeof(buffer_info));
894#endif
895
896	buffer_info.flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD;
897
898	if (!(card->pstream->state & AUICH_STATE_STARTED))
899		auich_stream_start(card->pstream, auich_play_inth, card->pstream);
900
901	if (!(card->rstream->state & AUICH_STATE_STARTED))
902		auich_stream_start(card->rstream, auich_record_inth, card->rstream);
903
904	if (acquire_sem_etc(card->buffer_ready_sem, 1, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT, 50000)
905		== B_TIMED_OUT) {
906		LOG(("buffer_exchange timeout ff\n"));
907	}
908
909	status = lock();
910
911	LIST_FOREACH(pstream, &card->streams, next) {
912		if ((pstream->use & AUICH_USE_PLAY) == 0 ||
913			(pstream->state & AUICH_STATE_STARTED) == 0)
914			continue;
915		if (pstream->update_needed)
916			break;
917	}
918
919	LIST_FOREACH(rstream, &card->streams, next) {
920		if ((rstream->use & AUICH_USE_RECORD) == 0 ||
921			(rstream->state & AUICH_STATE_STARTED) == 0)
922			continue;
923		if (rstream->update_needed)
924			break;
925	}
926
927	if (!pstream)
928		pstream = card->pstream;
929	if (!rstream)
930		rstream = card->rstream;
931
932	/* do playback */
933	buffer_info.playback_buffer_cycle = pstream->buffer_cycle;
934	buffer_info.played_real_time = pstream->real_time;
935	buffer_info.played_frames_count = pstream->frames_count;
936	buffer_info._reserved_0 = pstream->first_channel;
937	pstream->update_needed = false;
938
939	/* do record */
940	buffer_info.record_buffer_cycle = rstream->buffer_cycle;
941	buffer_info.recorded_frames_count = rstream->frames_count;
942	buffer_info.recorded_real_time = rstream->real_time;
943	buffer_info._reserved_1 = rstream->first_channel;
944	rstream->update_needed = false;
945	unlock(status);
946
947#ifdef __HAIKU__
948	if (user_memcpy(data, &buffer_info, sizeof(buffer_info)) < B_OK)
949		return B_BAD_ADDRESS;
950#else
951	memcpy(data, &buffer_info, sizeof(buffer_info));
952#endif
953
954	//TRACE(("buffer_exchange ended\n"));
955	return B_OK;
956}
957
958
959static status_t
960auich_buffer_force_stop(auich_dev *card)
961{
962	//auich_voice_halt(card->pvoice);
963	return B_OK;
964}
965
966
967#define cookie_type auich_dev
968#define get_description auich_get_description
969#define get_enabled_channels auich_get_enabled_channels
970#define get_global_format auich_get_global_format
971#define set_global_format auich_set_global_format
972#define list_mix_channels auich_list_mix_channels
973#define list_mix_controls auich_list_mix_controls
974#define list_mix_connections auich_list_mix_connections
975#define get_mix auich_get_mix
976#define set_mix auich_set_mix
977#define get_buffers auich_get_buffers
978#define buffer_exchange auich_buffer_exchange
979#define buffer_force_stop auich_buffer_force_stop
980#include "../generic/multi.c"
981
982
983static status_t
984auich_multi_control(void *cookie, uint32 op, void *arg, size_t length)
985{
986	auich_dev *card = (auich_dev *)cookie;
987
988	return multi_audio_control_generic(card, op, arg, length);
989}
990
991static status_t auich_open(const char *name, uint32 flags, void** cookie);
992static status_t auich_close(void* cookie);
993static status_t auich_free(void* cookie);
994static status_t auich_control(void* cookie, uint32 op, void* arg, size_t len);
995static status_t auich_read(void* cookie, off_t position, void *buf, size_t* num_bytes);
996static status_t auich_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes);
997
998device_hooks multi_hooks = {
999	auich_open, 			/* -> open entry point */
1000	auich_close, 			/* -> close entry point */
1001	auich_free,			/* -> free cookie */
1002	auich_control, 		/* -> control entry point */
1003	auich_read,			/* -> read entry point */
1004	auich_write,			/* -> write entry point */
1005	NULL,					/* start select */
1006	NULL,					/* stop select */
1007	NULL,					/* scatter-gather read from the device */
1008	NULL					/* scatter-gather write to the device */
1009};
1010
1011
1012static status_t
1013auich_open(const char *name, uint32 flags, void** cookie)
1014{
1015	auich_dev *card = NULL;
1016	void *settings_handle;
1017	int ix;
1018
1019	LOG(("open()\n"));
1020
1021	for (ix=0; ix<num_cards; ix++) {
1022		if (!strcmp(cards[ix].name, name)) {
1023			card = &cards[ix];
1024		}
1025	}
1026
1027	if (card == NULL) {
1028		LOG(("open() card not found %s\n", name));
1029		for (ix=0; ix<num_cards; ix++) {
1030			LOG(("open() card available %s\n", cards[ix].name));
1031		}
1032		return B_ERROR;
1033	}
1034
1035	LOG(("open() got card\n"));
1036
1037	if (card->pstream !=NULL)
1038		return B_ERROR;
1039	if (card->rstream !=NULL)
1040		return B_ERROR;
1041
1042	*cookie = card;
1043	card->multi.card = card;
1044
1045	// get driver settings
1046	settings_handle = load_driver_settings(AUICH_SETTINGS);
1047	if (settings_handle != NULL) {
1048		const char *item;
1049		char       *end;
1050		uint32      value;
1051
1052		item = get_driver_parameter (settings_handle, "sample_rate", "48000", "48000");
1053		value = strtoul (item, &end, 0);
1054		if (*end == '\0')
1055			current_settings.sample_rate = value;
1056
1057		item = get_driver_parameter (settings_handle, "buffer_frames", "256", "256");
1058		value = strtoul (item, &end, 0);
1059		if (*end == '\0')
1060			current_settings.buffer_frames = value;
1061
1062		item = get_driver_parameter (settings_handle, "buffer_count", "4", "4");
1063		value = strtoul (item, &end, 0);
1064		if (*end == '\0')
1065			current_settings.buffer_count = value;
1066
1067		unload_driver_settings(settings_handle);
1068	}
1069
1070	LOG(("stream_new\n"));
1071
1072	card->rstream = auich_stream_new(card, AUICH_USE_RECORD, current_settings.buffer_frames, current_settings.buffer_count);
1073	card->pstream = auich_stream_new(card, AUICH_USE_PLAY, current_settings.buffer_frames, current_settings.buffer_count);
1074
1075	card->buffer_ready_sem = create_sem(0, "pbuffer ready");
1076
1077	LOG(("stream_setaudio\n"));
1078
1079	auich_stream_set_audioparms(card->pstream, 2, true, current_settings.sample_rate);
1080	auich_stream_set_audioparms(card->rstream, 2, true, current_settings.sample_rate);
1081
1082	card->pstream->first_channel = 0;
1083	card->rstream->first_channel = 2;
1084
1085	auich_stream_commit_parms(card->pstream);
1086	auich_stream_commit_parms(card->rstream);
1087
1088	auich_create_channels_list(&card->multi);
1089
1090	return B_OK;
1091}
1092
1093
1094static status_t
1095auich_close(void* cookie)
1096{
1097	//auich_dev *card = cookie;
1098	LOG(("close()\n"));
1099
1100	return B_OK;
1101}
1102
1103
1104static status_t
1105auich_free(void* cookie)
1106{
1107	auich_dev *card = cookie;
1108	auich_stream *stream;
1109	LOG(("free()\n"));
1110
1111	if (card->buffer_ready_sem > B_OK)
1112			delete_sem(card->buffer_ready_sem);
1113
1114	LIST_FOREACH(stream, &card->streams, next) {
1115		auich_stream_halt(stream);
1116	}
1117
1118	while (!LIST_EMPTY(&card->streams)) {
1119		auich_stream_delete(LIST_FIRST(&card->streams));
1120	}
1121
1122	card->pstream = NULL;
1123	card->rstream = NULL;
1124
1125	return B_OK;
1126}
1127
1128
1129static status_t
1130auich_control(void* cookie, uint32 op, void* arg, size_t len)
1131{
1132	return auich_multi_control(cookie, op, arg, len);
1133}
1134
1135
1136static status_t
1137auich_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
1138{
1139	*num_bytes = 0;				/* tell caller nothing was read */
1140	return B_IO_ERROR;
1141}
1142
1143
1144static status_t
1145auich_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
1146{
1147	*num_bytes = 0;				/* tell caller nothing was written */
1148	return B_IO_ERROR;
1149}
1150