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