usb_ecm: Use the current configuration instead of a fixed one.
[haiku.git] / src / add-ons / kernel / drivers / audio / ac97 / geode / geode_multi.cpp
blob6a519e1b80dae9a29a0284ae082c4bf0beb0ba1c
1 /*
2 * Copyright 2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Jérôme Duval (korli@users.berlios.de)
7 */
10 #include "hmulti_audio.h"
11 #include "driver.h"
14 #ifdef TRACE
15 # undef TRACE
16 #endif
18 #define TRACE_MULTI_AUDIO
19 #ifdef TRACE_MULTI_AUDIO
20 # define TRACE(a...) dprintf("\33[34mgeode:\33[0m " a)
21 #else
22 # define TRACE(a...) ;
23 #endif
26 static multi_channel_info sChannels[] = {
27 { 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
28 { 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
29 { 2, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
30 { 3, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
31 { 4, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS,
32 B_CHANNEL_MINI_JACK_STEREO },
33 { 5, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS,
34 B_CHANNEL_MINI_JACK_STEREO },
35 { 6, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS,
36 B_CHANNEL_MINI_JACK_STEREO },
37 { 7, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS,
38 B_CHANNEL_MINI_JACK_STEREO },
42 static int32
43 format2size(uint32 format)
45 switch (format) {
46 case B_FMT_8BIT_S:
47 case B_FMT_16BIT:
48 return 2;
50 case B_FMT_18BIT:
51 case B_FMT_20BIT:
52 case B_FMT_24BIT:
53 case B_FMT_32BIT:
54 case B_FMT_FLOAT:
55 return 4;
57 default:
58 return -1;
63 static status_t
64 get_description(geode_controller* controller, multi_description* data)
66 data->interface_version = B_CURRENT_INTERFACE_VERSION;
67 data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
69 strcpy(data->friendly_name, "Geode");
70 strcpy(data->vendor_info, "Haiku");
72 int32 inChannels = 0;
73 if (controller->record_stream != NULL)
74 inChannels = 2;
76 int32 outChannels = 0;
77 if (controller->playback_stream != NULL)
78 outChannels = 2;
80 data->output_channel_count = outChannels;
81 data->output_bus_channel_count = outChannels;
82 data->input_channel_count = inChannels;
83 data->input_bus_channel_count = inChannels;
84 data->aux_bus_channel_count = 0;
86 dprintf("%s: request_channel_count: %ld\n", __func__,
87 data->request_channel_count);
89 if (data->request_channel_count >= (int)(sizeof(sChannels)
90 / sizeof(sChannels[0]))) {
91 memcpy(data->channels, &sChannels, sizeof(sChannels));
94 /* determine output/input rates */
95 data->output_rates = B_SR_48000;
96 data->input_rates = B_SR_48000;
98 /* force existance of 48kHz if variable rates are not supported */
99 if (data->output_rates == 0)
100 data->output_rates = B_SR_48000;
101 if (data->input_rates == 0)
102 data->input_rates = B_SR_48000;
104 data->max_cvsr_rate = 0;
105 data->min_cvsr_rate = 0;
107 data->output_formats = B_FMT_16BIT;
108 data->input_formats = B_FMT_16BIT;
109 data->lock_sources = B_MULTI_LOCK_INTERNAL;
110 data->timecode_sources = 0;
111 data->interface_flags = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
112 data->start_latency = 30000;
114 strcpy(data->control_panel, "");
116 return B_OK;
120 static status_t
121 get_enabled_channels(geode_controller* controller, multi_channel_enable* data)
123 B_SET_CHANNEL(data->enable_bits, 0, true);
124 B_SET_CHANNEL(data->enable_bits, 1, true);
125 B_SET_CHANNEL(data->enable_bits, 2, true);
126 B_SET_CHANNEL(data->enable_bits, 3, true);
127 data->lock_source = B_MULTI_LOCK_INTERNAL;
129 return B_OK;
133 static status_t
134 get_global_format(geode_controller* controller, multi_format_info* data)
136 data->output_latency = 0;
137 data->input_latency = 0;
138 data->timecode_kind = 0;
140 if (controller->playback_stream != NULL) {
141 data->output.format = controller->playback_stream->sample_format;
142 data->output.rate = controller->playback_stream->sample_rate;
143 } else {
144 data->output.format = 0;
145 data->output.rate = 0;
148 if (controller->record_stream != NULL) {
149 data->input.format = controller->record_stream->sample_format;
150 data->input.rate = controller->record_stream->sample_format;
151 } else {
152 data->input.format = 0;
153 data->input.rate = 0;
156 return B_OK;
160 static status_t
161 set_global_format(geode_controller* controller, multi_format_info* data)
163 // TODO: it looks like we're not supposed to fail; fix this!
164 #if 0
165 if ((data->output.format & audioGroup->supported_formats) == 0)
166 || (data->output.rate & audioGroup->supported_rates) == 0)
167 return B_BAD_VALUE;
168 #endif
170 if (controller->playback_stream != NULL) {
171 controller->playback_stream->sample_format = data->output.format;
172 controller->playback_stream->sample_rate = data->output.rate;
173 controller->playback_stream->sample_size = format2size(
174 controller->playback_stream->sample_format);
177 if (controller->record_stream != NULL) {
178 controller->record_stream->sample_rate = data->input.rate;
179 controller->record_stream->sample_format = data->input.format;
180 controller->record_stream->sample_size = format2size(
181 controller->record_stream->sample_format);
184 return B_OK;
188 static void
189 geode_ac97_get_mix(geode_controller *controller, const void *cookie, int32 type, float *values) {
190 ac97_source_info *info = (ac97_source_info *)cookie;
191 uint16 value, mask;
192 float gain;
194 switch(type) {
195 case B_MIX_GAIN:
196 value = ac97_reg_cached_read(controller->ac97, info->reg);
197 //TRACE("B_MIX_GAIN value : %u\n", value);
198 if (info->type & B_MIX_STEREO) {
199 mask = ((1 << (info->bits + 1)) - 1) << 8;
200 gain = ((value & mask) >> 8) * info->granularity;
201 if (info->polarity == 1)
202 values[0] = info->max_gain - gain;
203 else
204 values[0] = gain - info->min_gain;
206 mask = ((1 << (info->bits + 1)) - 1);
207 gain = (value & mask) * info->granularity;
208 if (info->polarity == 1)
209 values[1] = info->max_gain - gain;
210 else
211 values[1] = gain - info->min_gain;
212 } else {
213 mask = ((1 << (info->bits + 1)) - 1);
214 gain = (value & mask) * info->granularity;
215 if (info->polarity == 1)
216 values[0] = info->max_gain - gain;
217 else
218 values[0] = gain - info->min_gain;
220 break;
221 case B_MIX_MUTE:
222 mask = ((1 << 1) - 1) << 15;
223 value = ac97_reg_cached_read(controller->ac97, info->reg);
224 //TRACE("B_MIX_MUTE value : %u\n", value);
225 value &= mask;
226 values[0] = ((value >> 15) == 1) ? 1.0 : 0.0;
227 break;
228 case B_MIX_MICBOOST:
229 mask = ((1 << 1) - 1) << 6;
230 value = ac97_reg_cached_read(controller->ac97, info->reg);
231 //TRACE("B_MIX_MICBOOST value : %u\n", value);
232 value &= mask;
233 values[0] = ((value >> 6) == 1) ? 1.0 : 0.0;
234 break;
235 case B_MIX_MUX:
236 mask = ((1 << 3) - 1);
237 value = ac97_reg_cached_read(controller->ac97, AC97_RECORD_SELECT);
238 value &= mask;
239 //TRACE("B_MIX_MUX value : %u\n", value);
240 values[0] = (float)value;
241 break;
246 static void
247 geode_ac97_set_mix(geode_controller *controller, const void *cookie, int32 type, float *values) {
248 ac97_source_info *info = (ac97_source_info *)cookie;
249 uint16 value, mask;
250 float gain;
252 switch(type) {
253 case B_MIX_GAIN:
254 value = ac97_reg_cached_read(controller->ac97, info->reg);
255 if (info->type & B_MIX_STEREO) {
256 mask = ((1 << (info->bits + 1)) - 1) << 8;
257 value &= ~mask;
259 if (info->polarity == 1)
260 gain = info->max_gain - values[0];
261 else
262 gain = values[0] - info->min_gain;
263 value |= ((uint16)(gain / info->granularity) << 8) & mask;
265 mask = ((1 << (info->bits + 1)) - 1);
266 value &= ~mask;
267 if (info->polarity == 1)
268 gain = info->max_gain - values[1];
269 else
270 gain = values[1] - info->min_gain;
271 value |= ((uint16)(gain / info->granularity)) & mask;
272 } else {
273 mask = ((1 << (info->bits + 1)) - 1);
274 value &= ~mask;
275 if (info->polarity == 1)
276 gain = info->max_gain - values[0];
277 else
278 gain = values[0] - info->min_gain;
279 value |= ((uint16)(gain / info->granularity)) & mask;
281 //TRACE("B_MIX_GAIN value : %u\n", value);
282 ac97_reg_cached_write(controller->ac97, info->reg, value);
283 break;
284 case B_MIX_MUTE:
285 mask = ((1 << 1) - 1) << 15;
286 value = ac97_reg_cached_read(controller->ac97, info->reg);
287 value &= ~mask;
288 value |= ((values[0] == 1.0 ? 1 : 0 ) << 15 & mask);
289 if (info->reg == AC97_SURR_VOLUME) {
290 // there is a independent mute for each channel
291 mask = ((1 << 1) - 1) << 7;
292 value &= ~mask;
293 value |= ((values[0] == 1.0 ? 1 : 0 ) << 7 & mask);
295 //TRACE("B_MIX_MUTE value : %u\n", value);
296 ac97_reg_cached_write(controller->ac97, info->reg, value);
297 break;
298 case B_MIX_MICBOOST:
299 mask = ((1 << 1) - 1) << 6;
300 value = ac97_reg_cached_read(controller->ac97, info->reg);
301 value &= ~mask;
302 value |= ((values[0] == 1.0 ? 1 : 0 ) << 6 & mask);
303 //TRACE("B_MIX_MICBOOST value : %u\n", value);
304 ac97_reg_cached_write(controller->ac97, info->reg, value);
305 break;
306 case B_MIX_MUX:
307 mask = ((1 << 3) - 1);
308 value = ((int32)values[0]) & mask;
309 value = value | (value << 8);
310 //TRACE("B_MIX_MUX value : %u\n", value);
311 ac97_reg_cached_write(controller->ac97, AC97_RECORD_SELECT, value);
312 break;
318 static int32
319 create_group_control(geode_multi *multi, uint32 *index, uint32 parent,
320 strind_id string, const char* name) {
321 int32 i = *index;
322 (*index)++;
323 multi->controls[i].mix_control.id = MULTI_CONTROL_FIRSTID + i;
324 multi->controls[i].mix_control.parent = parent;
325 multi->controls[i].mix_control.flags = B_MULTI_MIX_GROUP;
326 multi->controls[i].mix_control.master = MULTI_CONTROL_MASTERID;
327 multi->controls[i].mix_control.string = string;
328 if (name)
329 strcpy(multi->controls[i].mix_control.name, name);
331 return multi->controls[i].mix_control.id;
335 static status_t
336 create_controls_list(geode_multi *multi)
338 uint32 i = 0, index = 0, count, id, parent, parent2, parent3;
339 const ac97_source_info *info;
341 /* AC97 Mixer */
342 parent = create_group_control(multi, &index, 0, S_null, "AC97 mixer");
344 count = source_info_size;
345 //Note that we ignore first item in source_info
346 //It's for recording, but do match this with ac97.c's source_info
347 for (i = 1; i < count ; i++) {
348 info = &source_info[i];
349 TRACE("name : %s\n", info->name);
351 parent2 = create_group_control(multi, &index, parent, S_null, info->name);
353 if (info->type & B_MIX_GAIN) {
354 if (info->type & B_MIX_MUTE) {
355 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
356 multi->controls[index].mix_control.flags = B_MULTI_MIX_ENABLE;
357 multi->controls[index].mix_control.master = MULTI_CONTROL_MASTERID;
358 multi->controls[index].mix_control.parent = parent2;
359 multi->controls[index].mix_control.string = S_MUTE;
360 multi->controls[index].cookie = info;
361 multi->controls[index].type = B_MIX_MUTE;
362 multi->controls[index].get = &geode_ac97_get_mix;
363 multi->controls[index].set = &geode_ac97_set_mix;
364 index++;
367 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
368 multi->controls[index].mix_control.flags = B_MULTI_MIX_GAIN;
369 multi->controls[index].mix_control.master = MULTI_CONTROL_MASTERID;
370 multi->controls[index].mix_control.parent = parent2;
371 strcpy(multi->controls[index].mix_control.name, info->name);
372 multi->controls[index].mix_control.gain.min_gain = info->min_gain;
373 multi->controls[index].mix_control.gain.max_gain = info->max_gain;
374 multi->controls[index].mix_control.gain.granularity = info->granularity;
375 multi->controls[index].cookie = info;
376 multi->controls[index].type = B_MIX_GAIN;
377 multi->controls[index].get = &geode_ac97_get_mix;
378 multi->controls[index].set = &geode_ac97_set_mix;
379 id = multi->controls[index].mix_control.id;
380 index++;
382 if (info->type & B_MIX_STEREO) {
383 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
384 multi->controls[index].mix_control.flags = B_MULTI_MIX_GAIN;
385 multi->controls[index].mix_control.master = id;
386 multi->controls[index].mix_control.parent = parent2;
387 strcpy(multi->controls[index].mix_control.name, info->name);
388 multi->controls[index].mix_control.gain.min_gain = info->min_gain;
389 multi->controls[index].mix_control.gain.max_gain = info->max_gain;
390 multi->controls[index].mix_control.gain.granularity = info->granularity;
391 multi->controls[index].cookie = info;
392 multi->controls[index].type = B_MIX_GAIN;
393 multi->controls[index].get = &geode_ac97_get_mix;
394 multi->controls[index].set = &geode_ac97_set_mix;
395 index++;
398 if (info->type & B_MIX_MICBOOST) {
399 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
400 multi->controls[index].mix_control.flags = B_MULTI_MIX_ENABLE;
401 multi->controls[index].mix_control.master = MULTI_CONTROL_MASTERID;
402 multi->controls[index].mix_control.parent = parent2;
403 strcpy(multi->controls[index].mix_control.name, "+20 dB");
404 multi->controls[index].cookie = info;
405 multi->controls[index].type = B_MIX_MICBOOST;
406 multi->controls[index].get = &geode_ac97_get_mix;
407 multi->controls[index].set = &geode_ac97_set_mix;
408 index++;
413 /* AC97 Record */
414 parent = create_group_control(multi, &index, 0, S_null, "Recording");
416 info = &source_info[0];
417 TRACE("name : %s\n", info->name);
419 parent2 = create_group_control(multi, &index, parent, S_null, info->name);
421 if (info->type & B_MIX_GAIN) {
422 if (info->type & B_MIX_MUTE) {
423 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
424 multi->controls[index].mix_control.flags = B_MULTI_MIX_ENABLE;
425 multi->controls[index].mix_control.master = MULTI_CONTROL_MASTERID;
426 multi->controls[index].mix_control.parent = parent2;
427 multi->controls[index].mix_control.string = S_MUTE;
428 multi->controls[index].cookie = info;
429 multi->controls[index].type = B_MIX_MUTE;
430 multi->controls[index].get = &geode_ac97_get_mix;
431 multi->controls[index].set = &geode_ac97_set_mix;
432 index++;
435 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
436 multi->controls[index].mix_control.flags = B_MULTI_MIX_GAIN;
437 multi->controls[index].mix_control.master = MULTI_CONTROL_MASTERID;
438 multi->controls[index].mix_control.parent = parent2;
439 strcpy(multi->controls[index].mix_control.name, info->name);
440 multi->controls[index].mix_control.gain.min_gain = info->min_gain;
441 multi->controls[index].mix_control.gain.max_gain = info->max_gain;
442 multi->controls[index].mix_control.gain.granularity = info->granularity;
443 multi->controls[index].cookie = info;
444 multi->controls[index].type = B_MIX_GAIN;
445 multi->controls[index].get = &geode_ac97_get_mix;
446 multi->controls[index].set = &geode_ac97_set_mix;
447 id = multi->controls[index].mix_control.id;
448 index++;
450 if (info->type & B_MIX_STEREO) {
451 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
452 multi->controls[index].mix_control.flags = B_MULTI_MIX_GAIN;
453 multi->controls[index].mix_control.master = id;
454 multi->controls[index].mix_control.parent = parent2;
455 strcpy(multi->controls[index].mix_control.name, info->name);
456 multi->controls[index].mix_control.gain.min_gain = info->min_gain;
457 multi->controls[index].mix_control.gain.max_gain = info->max_gain;
458 multi->controls[index].mix_control.gain.granularity = info->granularity;
459 multi->controls[index].cookie = info;
460 multi->controls[index].type = B_MIX_GAIN;
461 multi->controls[index].get = &geode_ac97_get_mix;
462 multi->controls[index].set = &geode_ac97_set_mix;
463 index++;
466 if (info->type & B_MIX_RECORDMUX) {
467 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
468 multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX;
469 multi->controls[index].mix_control.parent = parent2;
470 strcpy(multi->controls[index].mix_control.name, "Record mux");
471 multi->controls[index].cookie = info;
472 multi->controls[index].type = B_MIX_MUX;
473 multi->controls[index].get = &geode_ac97_get_mix;
474 multi->controls[index].set = &geode_ac97_set_mix;
475 parent3 = multi->controls[index].mix_control.id;
476 index++;
478 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
479 multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
480 multi->controls[index].mix_control.parent = parent3;
481 multi->controls[index].mix_control.string = S_MIC;
482 index++;
483 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
484 multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
485 multi->controls[index].mix_control.parent = parent3;
486 strcpy(multi->controls[index].mix_control.name, "CD in");
487 index++;
488 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
489 multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
490 multi->controls[index].mix_control.parent = parent3;
491 strcpy(multi->controls[index].mix_control.name, "Video in");
492 index++;
493 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
494 multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
495 multi->controls[index].mix_control.parent = parent3;
496 strcpy(multi->controls[index].mix_control.name, "Aux in");
497 index++;
498 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
499 multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
500 multi->controls[index].mix_control.parent = parent3;
501 strcpy(multi->controls[index].mix_control.name, "Line in");
502 index++;
503 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
504 multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
505 multi->controls[index].mix_control.parent = parent3;
506 multi->controls[index].mix_control.string = S_STEREO_MIX;
507 index++;
508 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
509 multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
510 multi->controls[index].mix_control.parent = parent3;
511 multi->controls[index].mix_control.string = S_MONO_MIX;
512 index++;
513 multi->controls[index].mix_control.id = MULTI_CONTROL_FIRSTID + index;
514 multi->controls[index].mix_control.flags = B_MULTI_MIX_MUX_VALUE;
515 multi->controls[index].mix_control.parent = parent3;
516 strcpy(multi->controls[index].mix_control.name, "TAD");
517 index++;
521 multi->control_count = index;
522 TRACE("multi->control_count %lu\n", multi->control_count);
523 return B_OK;
527 static status_t
528 list_mix_controls(geode_controller* controller, multi_mix_control_info* mmci)
530 multi_mix_control* mmc = mmci->controls;
531 if (mmci->control_count < 24)
532 return B_ERROR;
534 if (create_controls_list(controller->multi) < B_OK)
535 return B_ERROR;
536 for (uint32 i = 0; i < controller->multi->control_count; i++) {
537 mmc[i] = controller->multi->controls[i].mix_control;
540 mmci->control_count = controller->multi->control_count;
541 return B_OK;
545 static status_t
546 list_mix_connections(geode_controller* controller,
547 multi_mix_connection_info* data)
549 data->actual_count = 0;
550 return B_OK;
554 static status_t
555 list_mix_channels(geode_controller* controller, multi_mix_channel_info *data)
557 return B_OK;
561 static status_t
562 get_mix(geode_controller *controller, multi_mix_value_info * mmvi)
564 for (int32 i = 0; i < mmvi->item_count; i++) {
565 uint32 id = mmvi->values[i].id - MULTI_CONTROL_FIRSTID;
566 if (id < 0 || id >= controller->multi->control_count) {
567 dprintf("geode_get_mix : invalid control id requested : %li\n", id);
568 continue;
570 multi_mixer_control *control = &controller->multi->controls[id];
572 if (control->mix_control.flags & B_MULTI_MIX_GAIN) {
573 if (control->get) {
574 float values[2];
575 control->get(controller, control->cookie, control->type, values);
576 if (control->mix_control.master == MULTI_CONTROL_MASTERID)
577 mmvi->values[i].gain = values[0];
578 else
579 mmvi->values[i].gain = values[1];
583 if (control->mix_control.flags & B_MULTI_MIX_ENABLE && control->get) {
584 float values[1];
585 control->get(controller, control->cookie, control->type, values);
586 mmvi->values[i].enable = (values[0] == 1.0);
589 if (control->mix_control.flags & B_MULTI_MIX_MUX && control->get) {
590 float values[1];
591 control->get(controller, control->cookie, control->type, values);
592 mmvi->values[i].mux = (int32)values[0];
595 return B_OK;
599 static status_t
600 set_mix(geode_controller *controller, multi_mix_value_info * mmvi)
602 geode_multi *multi = controller->multi;
603 for (int32 i = 0; i < mmvi->item_count; i++) {
604 uint32 id = mmvi->values[i].id - MULTI_CONTROL_FIRSTID;
605 if (id < 0 || id >= multi->control_count) {
606 dprintf("geode_set_mix : invalid control id requested : %li\n", id);
607 continue;
609 multi_mixer_control *control = &multi->controls[id];
611 if (control->mix_control.flags & B_MULTI_MIX_GAIN) {
612 multi_mixer_control *control2 = NULL;
613 if (i+1<mmvi->item_count) {
614 id = mmvi->values[i + 1].id - MULTI_CONTROL_FIRSTID;
615 if (id < 0 || id >= multi->control_count) {
616 dprintf("geode_set_mix : invalid control id requested : %li\n", id);
617 } else {
618 control2 = &multi->controls[id];
619 if (control2->mix_control.master != control->mix_control.id)
620 control2 = NULL;
624 if (control->set) {
625 float values[2];
626 values[0] = 0.0;
627 values[1] = 0.0;
629 if (control->mix_control.master == MULTI_CONTROL_MASTERID)
630 values[0] = mmvi->values[i].gain;
631 else
632 values[1] = mmvi->values[i].gain;
634 if (control2 && control2->mix_control.master != MULTI_CONTROL_MASTERID)
635 values[1] = mmvi->values[i+1].gain;
637 control->set(controller, control->cookie, control->type, values);
640 if (control2)
641 i++;
644 if (control->mix_control.flags & B_MULTI_MIX_ENABLE && control->set) {
645 float values[1];
647 values[0] = mmvi->values[i].enable ? 1.0 : 0.0;
648 control->set(controller, control->cookie, control->type, values);
651 if (control->mix_control.flags & B_MULTI_MIX_MUX && control->set) {
652 float values[1];
654 values[0] = (float)mmvi->values[i].mux;
655 control->set(controller, control->cookie, control->type, values);
658 return B_OK;
662 static status_t
663 get_buffers(geode_controller* controller, multi_buffer_list* data)
665 TRACE("playback: %ld buffers, %ld channels, %ld samples\n",
666 data->request_playback_buffers, data->request_playback_channels,
667 data->request_playback_buffer_size);
668 TRACE("record: %ld buffers, %ld channels, %ld samples\n",
669 data->request_record_buffers, data->request_record_channels,
670 data->request_record_buffer_size);
672 /* Determine what buffers we return given the request */
674 data->return_playback_buffers = data->request_playback_buffers;
675 data->return_playback_channels = data->request_playback_channels;
676 data->return_playback_buffer_size = data->request_playback_buffer_size;
677 data->return_record_buffers = data->request_record_buffers;
678 data->return_record_channels = data->request_record_channels;
679 data->return_record_buffer_size = data->request_record_buffer_size;
681 /* Workaround for Haiku multi_audio API, since it prefers to let the
682 driver pick values, while the BeOS multi_audio actually gives the
683 user's defaults. */
684 if (data->return_playback_buffers > STREAM_MAX_BUFFERS
685 || data->return_playback_buffers < STREAM_MIN_BUFFERS)
686 data->return_playback_buffers = STREAM_MIN_BUFFERS;
688 if (data->return_record_buffers > STREAM_MAX_BUFFERS
689 || data->return_record_buffers < STREAM_MIN_BUFFERS)
690 data->return_record_buffers = STREAM_MIN_BUFFERS;
692 if (data->return_playback_buffer_size == 0)
693 data->return_playback_buffer_size = DEFAULT_FRAMES_PER_BUFFER;
695 if (data->return_record_buffer_size == 0)
696 data->return_record_buffer_size = DEFAULT_FRAMES_PER_BUFFER;
698 /* ... from here on, we can assume again that a reasonable request is
699 being made */
701 data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD;
703 /* Copy the settings into the streams */
705 if (controller->playback_stream != NULL) {
706 controller->playback_stream->num_buffers = data->return_playback_buffers;
707 controller->playback_stream->num_channels = data->return_playback_channels;
708 controller->playback_stream->buffer_length
709 = data->return_playback_buffer_size;
711 status_t status = geode_stream_setup_buffers(
712 controller->playback_stream, "Playback");
713 if (status != B_OK) {
714 dprintf("geode: Error setting up playback buffers: %s\n",
715 strerror(status));
716 return status;
720 if (controller->record_stream != NULL) {
721 controller->record_stream->num_buffers = data->return_record_buffers;
722 controller->record_stream->num_channels = data->return_record_channels;
723 controller->record_stream->buffer_length
724 = data->return_record_buffer_size;
726 status_t status = geode_stream_setup_buffers(
727 controller->record_stream, "Recording");
728 if (status != B_OK) {
729 dprintf("geode: Error setting up recording buffers: %s\n",
730 strerror(status));
731 return status;
735 /* Setup data structure for multi_audio API... */
737 if (controller->playback_stream != NULL) {
738 uint32 playbackSampleSize = controller->playback_stream->sample_size;
740 for (int32 i = 0; i < data->return_playback_buffers; i++) {
741 for (int32 channelIndex = 0;
742 channelIndex < data->return_playback_channels; channelIndex++) {
743 data->playback_buffers[i][channelIndex].base
744 = (char*)controller->playback_stream->buffers[i]
745 + playbackSampleSize * channelIndex;
746 data->playback_buffers[i][channelIndex].stride
747 = playbackSampleSize * data->return_playback_channels;
752 if (controller->record_stream != NULL) {
753 uint32 recordSampleSize = controller->record_stream->sample_size;
755 for (int32 i = 0; i < data->return_record_buffers; i++) {
756 for (int32 channelIndex = 0;
757 channelIndex < data->return_record_channels; channelIndex++) {
758 data->record_buffers[i][channelIndex].base
759 = (char*)controller->record_stream->buffers[i]
760 + recordSampleSize * channelIndex;
761 data->record_buffers[i][channelIndex].stride
762 = recordSampleSize * data->return_record_channels;
767 return B_OK;
771 /*! playback_buffer_cycle is the buffer we want to have played */
772 static status_t
773 buffer_exchange(geode_controller* controller, multi_buffer_info* data)
775 static int debug_buffers_exchanged = 0;
776 cpu_status status;
777 status_t err;
778 multi_buffer_info buffer_info;
780 if (controller->playback_stream == NULL)
781 return B_ERROR;
783 if (!controller->playback_stream->running) {
784 geode_stream_start(controller->playback_stream);
786 if (controller->record_stream && !controller->record_stream->running) {
787 geode_stream_start(controller->record_stream);
790 #ifdef __HAIKU__
791 if (user_memcpy(&buffer_info, data, sizeof(buffer_info)) < B_OK)
792 return B_BAD_ADDRESS;
793 #else
794 memcpy(&buffer_info, data, sizeof(buffer_info));
795 #endif
797 /* do playback */
798 err = acquire_sem_etc(controller->playback_stream->buffer_ready_sem,
799 1, B_CAN_INTERRUPT, 0);
800 if (err != B_OK) {
801 dprintf("%s: Error waiting for playback buffer to finish (%s)!\n", __func__,
802 strerror(err));
803 return err;
806 status = disable_interrupts();
807 acquire_spinlock(&controller->playback_stream->lock);
809 buffer_info.playback_buffer_cycle = controller->playback_stream->buffer_cycle;
810 buffer_info.played_real_time = controller->playback_stream->real_time;
811 buffer_info.played_frames_count = controller->playback_stream->frames_count;
813 release_spinlock(&controller->playback_stream->lock);
815 if (controller->record_stream) {
816 acquire_spinlock(&controller->record_stream->lock);
817 buffer_info.record_buffer_cycle = controller->record_stream->buffer_cycle;
818 buffer_info.recorded_real_time = controller->record_stream->real_time;
819 buffer_info.recorded_frames_count = controller->record_stream->frames_count;
820 release_spinlock(&controller->record_stream->lock);
823 restore_interrupts(status);
825 #ifdef __HAIKU__
826 if (user_memcpy(data, &buffer_info, sizeof(buffer_info)) < B_OK)
827 return B_BAD_ADDRESS;
828 #else
829 memcpy(data, &buffer_info, sizeof(buffer_info));
830 #endif
832 debug_buffers_exchanged++;
833 if (((debug_buffers_exchanged % 100) == 1) && (debug_buffers_exchanged < 1111)) {
834 dprintf("%s: %d buffers processed\n", __func__, debug_buffers_exchanged);
837 return B_OK;
841 static status_t
842 buffer_force_stop(geode_controller* controller)
844 if (controller->playback_stream != NULL) {
845 geode_stream_stop(controller->playback_stream);
847 if (controller->record_stream != NULL) {
848 geode_stream_stop(controller->record_stream);
851 return B_OK;
855 status_t
856 multi_audio_control(geode_controller* controller, uint32 op, void* arg, size_t len)
858 // TODO: make userland-safe when built for Haiku!
860 switch (op) {
861 case B_MULTI_GET_DESCRIPTION:
863 #ifdef __HAIKU__
864 multi_description description;
865 multi_channel_info channels[16];
866 multi_channel_info* originalChannels;
868 if (user_memcpy(&description, arg, sizeof(multi_description))
869 != B_OK)
870 return B_BAD_ADDRESS;
872 originalChannels = description.channels;
873 description.channels = channels;
874 if (description.request_channel_count > 16)
875 description.request_channel_count = 16;
877 status_t status = get_description(controller, &description);
878 if (status != B_OK)
879 return status;
881 description.channels = originalChannels;
882 if (user_memcpy(arg, &description, sizeof(multi_description))
883 != B_OK)
884 return B_BAD_ADDRESS;
885 return user_memcpy(originalChannels, channels, sizeof(multi_channel_info)
886 * description.request_channel_count);
887 #else
888 return get_description(controller, (multi_description*)arg);
889 #endif
892 case B_MULTI_GET_ENABLED_CHANNELS:
893 return get_enabled_channels(controller, (multi_channel_enable*)arg);
894 case B_MULTI_SET_ENABLED_CHANNELS:
895 return B_OK;
897 case B_MULTI_GET_GLOBAL_FORMAT:
898 return get_global_format(controller, (multi_format_info*)arg);
899 case B_MULTI_SET_GLOBAL_FORMAT:
900 return set_global_format(controller, (multi_format_info*)arg);
902 case B_MULTI_LIST_MIX_CHANNELS:
903 return list_mix_channels(controller, (multi_mix_channel_info*)arg);
904 case B_MULTI_LIST_MIX_CONTROLS:
905 return list_mix_controls(controller, (multi_mix_control_info*)arg);
906 case B_MULTI_LIST_MIX_CONNECTIONS:
907 return list_mix_connections(controller,
908 (multi_mix_connection_info*)arg);
909 case B_MULTI_GET_MIX:
910 return get_mix(controller, (multi_mix_value_info *)arg);
911 case B_MULTI_SET_MIX:
912 return set_mix(controller, (multi_mix_value_info *)arg);
914 case B_MULTI_GET_BUFFERS:
915 return get_buffers(controller, (multi_buffer_list*)arg);
917 case B_MULTI_BUFFER_EXCHANGE:
918 return buffer_exchange(controller, (multi_buffer_info*)arg);
919 case B_MULTI_BUFFER_FORCE_STOP:
920 return buffer_force_stop(controller);
922 case B_MULTI_GET_EVENT_INFO:
923 case B_MULTI_SET_EVENT_INFO:
924 case B_MULTI_GET_EVENT:
925 case B_MULTI_GET_CHANNEL_FORMATS:
926 case B_MULTI_SET_CHANNEL_FORMATS:
927 case B_MULTI_SET_BUFFERS:
928 case B_MULTI_SET_START_TIME:
929 return B_ERROR;
932 return B_BAD_VALUE;