xref: /haiku/src/add-ons/kernel/drivers/audio/ac97/auich/multi.c (revision dd2a1e350b303b855a50fd64e6cb55618be1ae6a)
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 
52 static void
53 auich_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 
111 static void
112 auich_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 
184 static int32
185 auich_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 
202 static status_t
203 auich_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 
394 static status_t
395 auich_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 
435 static status_t
436 auich_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 
501 static status_t
502 auich_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 
522 static status_t
523 auich_list_mix_connections(auich_dev *card, multi_mix_connection_info * data)
524 {
525 	return B_ERROR;
526 }
527 
528 
529 static status_t
530 auich_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 
568 static void
569 auich_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 
647 static status_t
648 auich_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 
719 static status_t
720 auich_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 
737 static status_t
738 auich_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 
758 static status_t
759 auich_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 
766 static status_t
767 auich_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 
838 static void
839 auich_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 
860 static void
861 auich_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 
882 static status_t
883 auich_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 
959 static status_t
960 auich_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 
983 static status_t
984 auich_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 
991 static status_t auich_open(const char *name, uint32 flags, void** cookie);
992 static status_t auich_close(void* cookie);
993 static status_t auich_free(void* cookie);
994 static status_t auich_control(void* cookie, uint32 op, void* arg, size_t len);
995 static status_t auich_read(void* cookie, off_t position, void *buf, size_t* num_bytes);
996 static status_t auich_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes);
997 
998 device_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 
1012 static status_t
1013 auich_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 
1094 static status_t
1095 auich_close(void* cookie)
1096 {
1097 	//auich_dev *card = cookie;
1098 	LOG(("close()\n"));
1099 
1100 	return B_OK;
1101 }
1102 
1103 
1104 static status_t
1105 auich_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 
1129 static status_t
1130 auich_control(void* cookie, uint32 op, void* arg, size_t len)
1131 {
1132 	return auich_multi_control(cookie, op, arg, len);
1133 }
1134 
1135 
1136 static status_t
1137 auich_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 
1144 static status_t
1145 auich_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