vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / audio / hda / hda_multi_audio.cpp
blob7557d732c2f24fa5f18aa9391e6959f9f11e9f8d
1 /*
2 * Copyright 2007-2010, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ithamar Adema, ithamar AT unet DOT nl
7 * Axel Dörfler, axeld@pinc-software.de
8 */
11 #include "hmulti_audio.h"
12 #include "driver.h"
15 #ifdef TRACE
16 # undef TRACE
17 #endif
19 //#define TRACE_MULTI_AUDIO
20 #ifdef TRACE_MULTI_AUDIO
21 # define TRACE(a...) dprintf("hda: " a)
22 #else
23 # define TRACE(a...) ;
24 #endif
25 #define ERROR(a...) dprintf("hda: " a)
27 typedef enum {
28 B_MIX_GAIN = 1 << 0,
29 B_MIX_MUTE = 1 << 1,
30 B_MIX_MUX_MIXER = 1 << 2,
31 B_MIX_MUX_SELECTOR = 1 << 3
32 } mixer_type;
35 static multi_channel_info sChannels[] = {
36 { 0, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
37 { 1, B_MULTI_OUTPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
38 { 2, B_MULTI_INPUT_CHANNEL, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS, 0 },
39 { 3, B_MULTI_INPUT_CHANNEL, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS, 0 },
40 { 4, B_MULTI_OUTPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS,
41 B_CHANNEL_MINI_JACK_STEREO },
42 { 5, B_MULTI_OUTPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS,
43 B_CHANNEL_MINI_JACK_STEREO },
44 { 6, B_MULTI_INPUT_BUS, B_CHANNEL_LEFT | B_CHANNEL_STEREO_BUS,
45 B_CHANNEL_MINI_JACK_STEREO },
46 { 7, B_MULTI_INPUT_BUS, B_CHANNEL_RIGHT | B_CHANNEL_STEREO_BUS,
47 B_CHANNEL_MINI_JACK_STEREO },
51 static int32
52 format2size(uint32 format)
54 switch (format) {
55 case B_FMT_8BIT_S:
56 case B_FMT_16BIT:
57 return 2;
59 case B_FMT_18BIT:
60 case B_FMT_20BIT:
61 case B_FMT_24BIT:
62 case B_FMT_32BIT:
63 case B_FMT_FLOAT:
64 return 4;
66 default:
67 return -1;
72 static status_t
73 get_description(hda_audio_group* audioGroup, multi_description* data)
75 data->interface_version = B_CURRENT_INTERFACE_VERSION;
76 data->interface_minimum = B_CURRENT_INTERFACE_VERSION;
78 strcpy(data->friendly_name, "HD Audio");
79 strcpy(data->vendor_info, "Haiku");
81 int32 inChannels = 0;
82 if (audioGroup->record_stream != NULL)
83 inChannels = 2;
85 int32 outChannels = 0;
86 if (audioGroup->playback_stream != NULL)
87 outChannels = 2;
89 data->output_channel_count = outChannels;
90 data->output_bus_channel_count = outChannels;
91 data->input_channel_count = inChannels;
92 data->input_bus_channel_count = inChannels;
93 data->aux_bus_channel_count = 0;
95 TRACE("%s: request_channel_count: %ld\n", __func__,
96 data->request_channel_count);
98 if (data->request_channel_count >= (int)(sizeof(sChannels)
99 / sizeof(sChannels[0]))) {
100 memcpy(data->channels, &sChannels, sizeof(sChannels));
103 if (audioGroup->playback_stream != NULL) {
104 data->output_rates = audioGroup->playback_stream->sample_rate;
105 data->output_formats = audioGroup->playback_stream->sample_format;
106 } else {
107 data->output_rates = 0;
108 data->output_formats = 0;
111 if (audioGroup->record_stream != NULL) {
112 data->input_rates = audioGroup->record_stream->sample_rate;
113 data->input_formats = audioGroup->record_stream->sample_format;
114 } else {
115 data->input_rates = 0;
116 data->input_formats = 0;
119 // force existance of 48kHz if variable rates are not supported
120 if (data->output_rates == 0)
121 data->output_rates = B_SR_48000;
122 if (data->input_rates == 0)
123 data->input_rates = B_SR_48000;
125 data->max_cvsr_rate = 0;
126 data->min_cvsr_rate = 0;
128 data->lock_sources = B_MULTI_LOCK_INTERNAL;
129 data->timecode_sources = 0;
130 data->interface_flags
131 = B_MULTI_INTERFACE_PLAYBACK | B_MULTI_INTERFACE_RECORD;
132 data->start_latency = 30000;
134 strcpy(data->control_panel, "");
136 return B_OK;
140 static status_t
141 get_enabled_channels(hda_audio_group* audioGroup, multi_channel_enable* data)
143 B_SET_CHANNEL(data->enable_bits, 0, true);
144 B_SET_CHANNEL(data->enable_bits, 1, true);
145 B_SET_CHANNEL(data->enable_bits, 2, true);
146 B_SET_CHANNEL(data->enable_bits, 3, true);
147 data->lock_source = B_MULTI_LOCK_INTERNAL;
149 return B_OK;
153 static status_t
154 get_global_format(hda_audio_group* audioGroup, multi_format_info* data)
156 data->output_latency = 0;
157 data->input_latency = 0;
158 data->timecode_kind = 0;
160 if (audioGroup->playback_stream != NULL) {
161 data->output.format = audioGroup->playback_stream->sample_format;
162 data->output.rate = audioGroup->playback_stream->sample_rate;
163 } else {
164 data->output.format = 0;
165 data->output.rate = 0;
168 if (audioGroup->record_stream != NULL) {
169 data->input.format = audioGroup->record_stream->sample_format;
170 data->input.rate = audioGroup->record_stream->sample_rate;
171 } else {
172 data->input.format = 0;
173 data->input.rate = 0;
176 return B_OK;
180 static status_t
181 set_global_format(hda_audio_group* audioGroup, multi_format_info* data)
183 // TODO: it looks like we're not supposed to fail; fix this!
184 #if 0
185 if ((data->output.format & audioGroup->supported_formats) == 0)
186 || (data->output.rate & audioGroup->supported_rates) == 0)
187 return B_BAD_VALUE;
188 #endif
190 if (audioGroup->playback_stream != NULL) {
191 audioGroup->playback_stream->sample_format = data->output.format;
192 audioGroup->playback_stream->sample_rate = data->output.rate;
193 audioGroup->playback_stream->sample_size = format2size(
194 audioGroup->playback_stream->sample_format);
197 if (audioGroup->record_stream != NULL) {
198 audioGroup->record_stream->sample_rate = data->input.rate;
199 audioGroup->record_stream->sample_format = data->input.format;
200 audioGroup->record_stream->sample_size = format2size(
201 audioGroup->record_stream->sample_format);
204 return B_OK;
208 static enum strind_id
209 hda_find_multi_string(hda_widget& widget)
211 switch (CONF_DEFAULT_DEVICE(widget.d.pin.config)) {
212 case PIN_DEV_CD:
213 return S_CD;
214 case PIN_DEV_LINE_IN:
215 case PIN_DEV_LINE_OUT:
216 return S_LINE;
217 case PIN_DEV_MIC_IN:
218 return S_MIC;
219 case PIN_DEV_AUX:
220 return S_AUX;
221 case PIN_DEV_SPDIF_IN:
222 case PIN_DEV_SPDIF_OUT:
223 return S_SPDIF;
224 case PIN_DEV_HEAD_PHONE_OUT:
225 return S_HEADPHONE;
227 ERROR("couln't find a string for widget %ld in hda_find_multi_string()\n",
228 widget.node_id);
229 return S_null;
233 static void
234 hda_find_multi_custom_string(hda_widget& widget, char* custom, uint32 size)
236 const char* device = NULL;
237 switch (CONF_DEFAULT_DEVICE(widget.d.pin.config)) {
238 case PIN_DEV_LINE_IN:
239 device = "Line in";
240 case PIN_DEV_LINE_OUT:
241 if (device == NULL)
242 device = "Line out";
243 case PIN_DEV_MIC_IN:
244 if (device == NULL)
245 device = "Mic in";
246 switch (CONF_DEFAULT_COLOR(widget.d.pin.config)) {
247 case 1:
248 device = "Rear";
249 break;
250 case 2:
251 device = "Side";
252 break;
253 case 3:
254 device = "Line in";
255 break;
256 case 4:
257 device = "Front";
258 break;
259 case 6:
260 device = "Center/Sub";
261 break;
262 case 9:
263 device = "Mic in";
264 break;
266 break;
267 case PIN_DEV_SPDIF_IN:
268 device = "SPDIF in";
269 break;
270 case PIN_DEV_SPDIF_OUT:
271 device = "SPDIF out";
272 break;
273 case PIN_DEV_CD:
274 device = "CD";
275 break;
276 case PIN_DEV_HEAD_PHONE_OUT:
277 device = "Headphones";
278 break;
279 case PIN_DEV_SPEAKER:
280 device = "Speaker";
281 break;
283 if (device == NULL) {
284 ERROR("couldn't find a string for widget %ld in "
285 "hda_find_multi_custom_string()\n", widget.node_id);
288 const char* location
289 = get_widget_location(CONF_DEFAULT_LOCATION(widget.d.pin.config));
290 snprintf(custom, size, "%s%s%s", location ? location : "",
291 location ? " " : "", device);
295 static int32
296 hda_create_group_control(hda_multi *multi, uint32 *index, int32 parent,
297 enum strind_id string, const char* name)
299 uint32 i = *index;
300 (*index)++;
301 multi->controls[i].mix_control.id = MULTI_CONTROL_FIRSTID + i;
302 multi->controls[i].mix_control.parent = parent;
303 multi->controls[i].mix_control.flags = B_MULTI_MIX_GROUP;
304 multi->controls[i].mix_control.master = MULTI_CONTROL_MASTERID;
305 multi->controls[i].mix_control.string = string;
306 if (name)
307 strcpy(multi->controls[i].mix_control.name, name);
309 return multi->controls[i].mix_control.id;
313 static void
314 hda_create_channel_control(hda_multi* multi, uint32* index, int32 parent,
315 int32 string, hda_widget& widget, bool input, uint32 capabilities,
316 int32 inputIndex, bool& gain, bool& mute)
318 uint32 i = *index, id;
319 hda_multi_mixer_control control;
321 control.nid = widget.node_id;
322 control.input = input;
323 control.mute = 0;
324 control.gain = 0;
325 control.capabilities = capabilities;
326 control.index = inputIndex;
327 control.mix_control.master = MULTI_CONTROL_MASTERID;
328 control.mix_control.parent = parent;
330 if (mute && (capabilities & AMP_CAP_MUTE) != 0) {
331 control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
332 control.mix_control.flags = B_MULTI_MIX_ENABLE;
333 control.mix_control.string = S_MUTE;
334 control.type = B_MIX_MUTE;
335 multi->controls[i++] = control;
336 TRACE("control nid %ld mute\n", control.nid);
337 mute = false;
340 if (gain && AMP_CAP_NUM_STEPS(capabilities) >= 1) {
341 control.mix_control.gain.granularity = AMP_CAP_STEP_SIZE(capabilities);
342 control.mix_control.gain.min_gain = (0.0 - AMP_CAP_OFFSET(capabilities))
343 * control.mix_control.gain.granularity;
344 control.mix_control.gain.max_gain = (AMP_CAP_NUM_STEPS(capabilities)
345 - AMP_CAP_OFFSET(capabilities))
346 * control.mix_control.gain.granularity;
348 control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
349 control.mix_control.flags = B_MULTI_MIX_GAIN;
350 control.mix_control.string = S_null;
351 control.type = B_MIX_GAIN;
352 strcpy(control.mix_control.name, "Gain");
353 multi->controls[i++] = control;
354 id = control.mix_control.id;
356 // second channel
357 control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
358 control.mix_control.master = id;
359 multi->controls[i++] = control;
360 TRACE("control nid %ld %f min %f max %f\n", control.nid,
361 control.mix_control.gain.granularity,
362 control.mix_control.gain.min_gain,
363 control.mix_control.gain.max_gain);
364 gain = false;
367 *index = i;
371 static void
372 hda_create_mux_control(hda_multi *multi, uint32 *index, int32 parent,
373 hda_widget& widget)
375 uint32 i = *index, parent2;
376 hda_multi_mixer_control control;
377 hda_audio_group *audioGroup = multi->group;
379 control.nid = widget.node_id;
380 control.input = true;
381 control.mute = 0;
382 control.gain = 0;
383 control.mix_control.master = MULTI_CONTROL_MASTERID;
384 control.mix_control.parent = parent;
385 control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
386 control.mix_control.flags = B_MULTI_MIX_MUX;
387 control.mix_control.string = S_null;
388 control.type = widget.type == WT_AUDIO_MIXER
389 ? B_MIX_MUX_MIXER : B_MIX_MUX_SELECTOR;
390 multi->controls[i] = control;
391 strcpy(multi->controls[i].mix_control.name, "");
392 i++;
393 parent2 = control.mix_control.id;
395 for (uint32 j = 0; j < widget.num_inputs; j++) {
396 hda_widget *input =
397 hda_audio_group_get_widget(audioGroup, widget.inputs[j]);
398 if (input->type != WT_PIN_COMPLEX)
399 continue;
400 control.nid = widget.node_id;
401 control.input = true;
402 control.mix_control.id = MULTI_CONTROL_FIRSTID + i;
403 control.mix_control.flags = B_MULTI_MIX_MUX_VALUE;
404 control.mix_control.parent = parent2;
405 control.mix_control.string = S_null;
406 multi->controls[i] = control;
407 hda_find_multi_custom_string(*input,
408 multi->controls[i].mix_control.name,
409 sizeof(multi->controls[i].mix_control.name));
410 i++;
413 *index = i;
417 static void
418 hda_create_control_for_complex(hda_multi* multi, uint32* index, uint32 parent,
419 hda_widget& widget, bool& gain, bool& mute)
421 hda_audio_group* audioGroup = multi->group;
423 switch (widget.type) {
424 case WT_AUDIO_OUTPUT:
425 case WT_AUDIO_MIXER:
426 case WT_AUDIO_SELECTOR:
427 case WT_PIN_COMPLEX:
428 break;
429 default:
430 return;
433 if ((widget.flags & WIDGET_FLAG_WIDGET_PATH) != 0)
434 return;
436 TRACE(" create widget nid %lu\n", widget.node_id);
437 hda_create_channel_control(multi, index, parent, 0,
438 widget, false, widget.capabilities.output_amplifier, 0, gain, mute);
440 if (!gain && !mute) {
441 widget.flags |= WIDGET_FLAG_WIDGET_PATH;
442 return;
445 if (widget.type == WT_AUDIO_MIXER) {
446 hda_create_channel_control(multi, index, parent, 0,
447 widget, true, widget.capabilities.input_amplifier, 0, gain, mute);
448 if (!gain && !mute) {
449 widget.flags |= WIDGET_FLAG_WIDGET_PATH;
450 return;
454 if (widget.type != WT_AUDIO_OUTPUT && widget.num_inputs > 0) {
455 hda_widget& child = *hda_audio_group_get_widget(audioGroup,
456 widget.inputs[widget.active_input]);
457 hda_create_control_for_complex(multi, index, parent, child, gain, mute);
460 widget.flags |= WIDGET_FLAG_WIDGET_PATH;
464 static status_t
465 hda_create_controls_list(hda_multi* multi)
467 uint32 index = 0;
468 hda_audio_group* audioGroup = multi->group;
470 uint32 parent = hda_create_group_control(multi, &index, 0, S_OUTPUT, NULL);
471 uint32 parent2;
473 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
474 hda_widget& complex = audioGroup->widgets[i];
475 char name[48];
477 if (complex.type != WT_PIN_COMPLEX)
478 continue;
479 if (!PIN_CAP_IS_OUTPUT(complex.d.pin.capabilities))
480 continue;
481 if ((complex.flags & WIDGET_FLAG_OUTPUT_PATH) == 0)
482 continue;
484 TRACE("create complex nid %lu\n", complex.node_id);
485 hda_find_multi_custom_string(complex, name, sizeof(name));
486 parent2 = hda_create_group_control(multi, &index, parent, S_null, name);
487 bool gain = true, mute = true;
489 hda_create_control_for_complex(multi, &index, parent2, complex, gain,
490 mute);
493 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
494 hda_widget& widget = audioGroup->widgets[i];
496 if (widget.type != WT_AUDIO_MIXER)
497 continue;
498 if ((widget.flags & WIDGET_FLAG_WIDGET_PATH) != 0)
499 continue;
501 TRACE("create widget nid %lu\n", widget.node_id);
503 if (AMP_CAP_NUM_STEPS(widget.capabilities.input_amplifier) >= 1) {
504 for (uint32 j = 0; j < widget.num_inputs; j++) {
505 hda_widget* complex = hda_audio_group_get_widget(audioGroup,
506 widget.inputs[j]);
507 char name[48];
508 if (complex->type != WT_PIN_COMPLEX)
509 continue;
510 if (!PIN_CAP_IS_INPUT(complex->d.pin.capabilities))
511 continue;
512 if ((complex->flags & WIDGET_FLAG_OUTPUT_PATH) != 0)
513 continue;
514 TRACE(" create widget input nid %lu\n", widget.inputs[j]);
515 hda_find_multi_custom_string(*complex, name, sizeof(name));
516 parent2 = hda_create_group_control(multi, &index,
517 parent, S_null, name);
518 bool gain = true, mute = true;
519 hda_create_channel_control(multi, &index, parent2, 0, widget,
520 true, widget.capabilities.input_amplifier, j, gain, mute);
524 widget.flags |= WIDGET_FLAG_WIDGET_PATH;
527 parent = hda_create_group_control(multi, &index, 0, S_INPUT, NULL);
529 for (uint32 i = 0; i < audioGroup->widget_count; i++) {
530 hda_widget& widget = audioGroup->widgets[i];
532 if (widget.type != WT_AUDIO_INPUT)
533 continue;
535 uint32 capabilities = widget.capabilities.input_amplifier;
536 if (AMP_CAP_NUM_STEPS(capabilities) < 1)
537 continue;
539 parent2 = hda_create_group_control(multi, &index,
540 parent, hda_find_multi_string(widget), "Input");
541 bool gain = true, mute = true;
542 hda_create_channel_control(multi, &index, parent2, 0,
543 widget, true, capabilities, 0, gain, mute);
545 if (widget.num_inputs > 1) {
546 TRACE(" create mux for nid %lu\n", widget.node_id);
547 hda_create_mux_control(multi, &index, parent2, widget);
548 continue;
551 hda_widget *mixer = hda_audio_group_get_widget(audioGroup,
552 widget.inputs[0]);
553 if (mixer->type != WT_AUDIO_MIXER && mixer->type != WT_AUDIO_SELECTOR)
554 continue;
555 TRACE(" create mixer nid %lu\n", mixer->node_id);
556 hda_create_mux_control(multi, &index, parent2, *mixer);
559 multi->control_count = index;
560 TRACE("multi->control_count %lu\n", multi->control_count);
561 return B_OK;
565 static status_t
566 list_mix_controls(hda_audio_group* audioGroup, multi_mix_control_info* mmci)
568 multi_mix_control *mmc = mmci->controls;
569 if (mmci->control_count < 24)
570 return B_ERROR;
572 if (hda_create_controls_list(audioGroup->multi) < B_OK)
573 return B_ERROR;
574 for (uint32 i = 0; i < audioGroup->multi->control_count; i++) {
575 mmc[i] = audioGroup->multi->controls[i].mix_control;
578 mmci->control_count = audioGroup->multi->control_count;
579 return B_OK;
583 static status_t
584 list_mix_connections(hda_audio_group* audioGroup,
585 multi_mix_connection_info* data)
587 data->actual_count = 0;
588 return B_OK;
592 static status_t
593 list_mix_channels(hda_audio_group* audioGroup, multi_mix_channel_info *data)
595 return B_OK;
599 static void
600 get_control_gain_mute(hda_audio_group* audioGroup,
601 hda_multi_mixer_control *control, uint32 *resp)
603 uint32 verb[2];
604 verb[0] = MAKE_VERB(audioGroup->codec->addr,
605 control->nid,
606 VID_GET_AMPLIFIER_GAIN_MUTE,
607 (control->input ? AMP_GET_INPUT : AMP_GET_OUTPUT)
608 | AMP_GET_LEFT_CHANNEL | AMP_GET_INPUT_INDEX(control->index));
609 verb[1] = MAKE_VERB(audioGroup->codec->addr,
610 control->nid,
611 VID_GET_AMPLIFIER_GAIN_MUTE,
612 (control->input ? AMP_GET_INPUT : AMP_GET_OUTPUT)
613 | AMP_GET_RIGHT_CHANNEL | AMP_GET_INPUT_INDEX(control->index));
614 hda_send_verbs(audioGroup->codec, verb, resp, 2);
618 static status_t
619 get_mix(hda_audio_group* audioGroup, multi_mix_value_info * mmvi)
621 int32 id;
622 hda_multi_mixer_control *control = NULL;
623 for (int32 i = 0; i < mmvi->item_count; i++) {
624 id = mmvi->values[i].id - MULTI_CONTROL_FIRSTID;
625 if (id < 0 || id >= audioGroup->multi->control_count) {
626 dprintf("hda: get_mix : invalid control id requested : %li\n", id);
627 continue;
629 control = &audioGroup->multi->controls[id];
631 if ((control->mix_control.flags
632 & (B_MULTI_MIX_GAIN | B_MULTI_MIX_ENABLE)) != 0) {
633 uint32 resp[2];
634 get_control_gain_mute(audioGroup, control, resp);
635 if ((control->mix_control.flags & B_MULTI_MIX_ENABLE) != 0) {
636 mmvi->values[i].enable = (resp[0] & AMP_MUTE) != 0;
637 TRACE("get_mix: %ld mute: %d\n", control->nid,
638 mmvi->values[i].enable);
639 } else if ((control->mix_control.flags & B_MULTI_MIX_GAIN) != 0) {
640 uint32 value;
641 if (control->mix_control.master == MULTI_CONTROL_MASTERID)
642 value = resp[0] & AMP_GAIN_MASK;
643 else
644 value = resp[1] & AMP_GAIN_MASK;
645 mmvi->values[i].gain = (0.0 + value - AMP_CAP_OFFSET(control->capabilities))
646 * AMP_CAP_STEP_SIZE(control->capabilities);
647 TRACE("get_mix: %ld gain: %f (%ld)\n", control->nid, mmvi->values[i].gain, value);
650 } else if ((control->mix_control.flags & B_MIX_MUX_MIXER) != 0) {
651 hda_widget* mixer = hda_audio_group_get_widget(audioGroup,
652 control->nid);
653 mmvi->values[i].mux = 0;
654 for (uint32 j = 0; j < mixer->num_inputs; j++) {
655 uint32 verb = MAKE_VERB(audioGroup->codec->addr,
656 control->nid, VID_GET_AMPLIFIER_GAIN_MUTE, AMP_GET_INPUT
657 | AMP_GET_LEFT_CHANNEL | AMP_GET_INPUT_INDEX(j));
658 uint32 resp;
659 if (hda_send_verbs(audioGroup->codec, &verb, &resp, 1) == B_OK) {
660 TRACE("get_mix: %ld mixer %ld is %smute\n", control->nid,
661 j, (resp & AMP_MUTE) != 0 ? "" : "un");
662 if ((resp & AMP_MUTE) == 0) {
663 mmvi->values[i].mux = j;
664 #ifndef TRACE_MULTI_AUDIO
665 break;
666 #endif
670 TRACE("get_mix: %ld mixer: %ld\n", control->nid,
671 mmvi->values[i].mux);
672 } else if ((control->mix_control.flags & B_MIX_MUX_SELECTOR) != 0) {
673 uint32 verb = MAKE_VERB(audioGroup->codec->addr, control->nid,
674 VID_GET_CONNECTION_SELECT, 0);
675 uint32 resp;
676 if (hda_send_verbs(audioGroup->codec, &verb, &resp, 1) == B_OK)
677 mmvi->values[i].mux = resp & 0xff;
678 TRACE("get_mix: %ld selector: %ld\n", control->nid,
679 mmvi->values[i].mux);
682 return B_OK;
686 static status_t
687 set_mix(hda_audio_group* audioGroup, multi_mix_value_info * mmvi)
689 int32 id;
690 hda_multi_mixer_control *control = NULL;
691 for (int32 i = 0; i < mmvi->item_count; i++) {
692 id = mmvi->values[i].id - MULTI_CONTROL_FIRSTID;
693 if (id < 0 || id >= audioGroup->multi->control_count) {
694 dprintf("set_mix : invalid control id requested : %li\n", id);
695 continue;
697 control = &audioGroup->multi->controls[id];
699 if ((control->mix_control.flags & B_MULTI_MIX_ENABLE) != 0) {
700 control->mute = (mmvi->values[i].enable ? AMP_MUTE : 0);
701 TRACE("set_mix: %ld mute: %lx\n", control->nid, control->mute);
702 uint32 resp[2];
703 get_control_gain_mute(audioGroup, control, resp);
705 uint32 verb[2];
706 verb[0] = MAKE_VERB(audioGroup->codec->addr,
707 control->nid,
708 VID_SET_AMPLIFIER_GAIN_MUTE,
709 (control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
710 | AMP_SET_LEFT_CHANNEL
711 | AMP_SET_INPUT_INDEX(control->index)
712 | control->mute
713 | (resp[0] & AMP_GAIN_MASK));
714 TRACE("set_mix: sending verb to %ld: %lx %lx %x %lx\n", control->nid,
715 control->mute, resp[0] & AMP_GAIN_MASK, control->input,
716 (control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
717 | AMP_SET_LEFT_CHANNEL
718 | AMP_SET_INPUT_INDEX(control->index)
719 | control->mute
720 | (resp[0] & AMP_GAIN_MASK));
721 verb[1] = MAKE_VERB(audioGroup->codec->addr,
722 control->nid,
723 VID_SET_AMPLIFIER_GAIN_MUTE,
724 (control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
725 | AMP_SET_RIGHT_CHANNEL
726 | AMP_SET_INPUT_INDEX(control->index)
727 | control->mute
728 | (resp[1] & AMP_GAIN_MASK));
729 TRACE("set_mix: ctrl2 sending verb to %ld: %lx %lx %x\n", control->nid,
730 control->mute, resp[1] & AMP_GAIN_MASK, control->input);
731 hda_send_verbs(audioGroup->codec, verb, NULL, 2);
732 } else if ((control->mix_control.flags & B_MULTI_MIX_GAIN) != 0) {
733 hda_multi_mixer_control *control2 = NULL;
734 if (i+1<mmvi->item_count) {
735 id = mmvi->values[i + 1].id - MULTI_CONTROL_FIRSTID;
736 if (id < 0 || id >= audioGroup->multi->control_count) {
737 dprintf("set_mix : invalid control id requested : %li\n", id);
738 } else {
739 control2 = &audioGroup->multi->controls[id];
740 if (control2->mix_control.master != control->mix_control.id)
741 control2 = NULL;
745 if (control->mix_control.master == MULTI_CONTROL_MASTERID) {
746 control->gain = (uint32)(mmvi->values[i].gain
747 / AMP_CAP_STEP_SIZE(control->capabilities)
748 + AMP_CAP_OFFSET(control->capabilities));
751 if (control2
752 && control2->mix_control.master != MULTI_CONTROL_MASTERID) {
753 control2->gain = (uint32)(mmvi->values[i+1].gain
754 / AMP_CAP_STEP_SIZE(control2->capabilities)
755 + AMP_CAP_OFFSET(control2->capabilities));
757 TRACE("set_mix: %ld gain: %lx and %ld gain: %lx\n",
758 control->nid, control->gain, control2->nid, control2->gain);
759 uint32 resp[2];
760 get_control_gain_mute(audioGroup, control, resp);
761 control->mute = resp[0] & AMP_MUTE;
762 if (control2)
763 control2->mute = resp[1] & AMP_MUTE;
765 uint32 verb[2];
766 verb[0] = MAKE_VERB(audioGroup->codec->addr,
767 control->nid,
768 VID_SET_AMPLIFIER_GAIN_MUTE,
769 (control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
770 | AMP_SET_LEFT_CHANNEL
771 | AMP_SET_INPUT_INDEX(control->index)
772 | (control->mute & AMP_MUTE)
773 | (control->gain & AMP_GAIN_MASK));
774 TRACE("set_mix: sending verb to %ld: %lx %lx %x %lx\n", control->nid,
775 control->mute, control->gain, control->input,
776 (control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
777 | AMP_SET_LEFT_CHANNEL
778 | AMP_SET_INPUT_INDEX(control->index)
779 | (control->mute & AMP_MUTE)
780 | (control->gain & AMP_GAIN_MASK));
781 if (control2) {
782 verb[1] = MAKE_VERB(audioGroup->codec->addr,
783 control2->nid,
784 VID_SET_AMPLIFIER_GAIN_MUTE,
785 (control->input ? AMP_SET_INPUT : AMP_SET_OUTPUT)
786 | AMP_SET_RIGHT_CHANNEL
787 | AMP_SET_INPUT_INDEX(control->index)
788 | (control2->mute & AMP_MUTE)
789 | (control2->gain & AMP_GAIN_MASK));
790 TRACE("set_mix: ctrl2 sending verb to %ld: %lx %lx %x\n",
791 control2->nid, control2->mute, control2->gain,
792 control2->input);
794 hda_send_verbs(audioGroup->codec, verb, NULL, control2 ? 2 : 1);
796 if (control2)
797 i++;
798 } else if ((control->mix_control.flags & B_MIX_MUX_MIXER) != 0) {
799 TRACE("set_mix: %ld mixer: %ld\n", control->nid, mmvi->values[i].mux);
800 hda_widget *mixer = hda_audio_group_get_widget(audioGroup,
801 control->nid);
802 uint32 verb[mixer->num_inputs];
803 for (uint32 j = 0; j < mixer->num_inputs; j++) {
804 verb[j] = MAKE_VERB(audioGroup->codec->addr,
805 control->nid, VID_SET_AMPLIFIER_GAIN_MUTE, AMP_SET_INPUT
806 | AMP_SET_LEFT_CHANNEL | AMP_SET_RIGHT_CHANNEL
807 | AMP_SET_INPUT_INDEX(j)
808 | ((mmvi->values[i].mux == j) ? 0 : AMP_MUTE));
809 TRACE("set_mix: %ld mixer %smuting %ld (%lx)\n", control->nid,
810 (mmvi->values[i].mux == j) ? "un" : "", j, verb[j]);
812 if (hda_send_verbs(audioGroup->codec, verb, NULL, mixer->num_inputs)
813 != B_OK)
814 dprintf("hda: Setting mixer %ld failed on widget %ld!\n",
815 mmvi->values[i].mux, control->nid);
816 } else if ((control->mix_control.flags & B_MIX_MUX_SELECTOR) != 0) {
817 uint32 verb = MAKE_VERB(audioGroup->codec->addr, control->nid,
818 VID_SET_CONNECTION_SELECT, mmvi->values[i].mux);
819 if (hda_send_verbs(audioGroup->codec, &verb, NULL, 1) != B_OK) {
820 dprintf("hda: Setting output selector %ld failed on widget "
821 "%ld!\n", mmvi->values[i].mux, control->nid);
823 TRACE("set_mix: %ld selector: %ld\n", control->nid,
824 mmvi->values[i].mux);
827 return B_OK;
831 static uint32
832 default_buffer_length_for_rate(uint32 rate)
834 // keep the latency about the same as 2048 frames per buffer at 44100 Hz
835 switch (rate) {
836 case B_SR_8000:
837 return 512;
838 case B_SR_11025:
839 return 512;
840 case B_SR_16000:
841 return 1024;
842 case B_SR_22050:
843 return 1024;
844 case B_SR_32000:
845 return 2048;
846 case B_SR_44100:
847 return 2048;
848 case B_SR_48000:
849 return 2048;
850 case B_SR_88200:
851 return 4096;
852 case B_SR_96000:
853 return 6144;
854 case B_SR_176400:
855 return 8192;
856 case B_SR_192000:
857 return 10240;
858 case B_SR_384000:
859 return 16384;
861 return 2048;
865 static status_t
866 get_buffers(hda_audio_group* audioGroup, multi_buffer_list* data)
868 TRACE("playback: %ld buffers, %ld channels, %ld samples\n",
869 data->request_playback_buffers, data->request_playback_channels,
870 data->request_playback_buffer_size);
871 TRACE("record: %ld buffers, %ld channels, %ld samples\n",
872 data->request_record_buffers, data->request_record_channels,
873 data->request_record_buffer_size);
875 /* Determine what buffers we return given the request */
877 data->return_playback_buffers = data->request_playback_buffers;
878 data->return_playback_channels = data->request_playback_channels;
879 data->return_playback_buffer_size = data->request_playback_buffer_size;
880 data->return_record_buffers = data->request_record_buffers;
881 data->return_record_channels = data->request_record_channels;
882 data->return_record_buffer_size = data->request_record_buffer_size;
884 /* Workaround for Haiku multi_audio API, since it prefers to let the
885 driver pick values, while the BeOS multi_audio actually gives the
886 user's defaults. */
887 if (data->return_playback_buffers > STREAM_MAX_BUFFERS
888 || data->return_playback_buffers < STREAM_MIN_BUFFERS)
889 data->return_playback_buffers = STREAM_MIN_BUFFERS;
891 if (data->return_record_buffers > STREAM_MAX_BUFFERS
892 || data->return_record_buffers < STREAM_MIN_BUFFERS)
893 data->return_record_buffers = STREAM_MIN_BUFFERS;
895 if (data->return_playback_buffer_size == 0
896 && audioGroup->playback_stream != NULL) {
897 data->return_playback_buffer_size = default_buffer_length_for_rate(
898 audioGroup->playback_stream->sample_rate);
901 if (data->return_record_buffer_size == 0
902 && audioGroup->record_stream != NULL) {
903 data->return_record_buffer_size = default_buffer_length_for_rate(
904 audioGroup->record_stream->sample_rate);
907 /* ... from here on, we can assume again that a reasonable request is
908 being made */
910 data->flags = B_MULTI_BUFFER_PLAYBACK | B_MULTI_BUFFER_RECORD;
912 /* Copy the settings into the streams */
914 if (audioGroup->playback_stream != NULL) {
915 audioGroup->playback_stream->num_buffers = data->return_playback_buffers;
916 audioGroup->playback_stream->num_channels = data->return_playback_channels;
917 audioGroup->playback_stream->buffer_length
918 = data->return_playback_buffer_size;
920 status_t status = hda_stream_setup_buffers(audioGroup,
921 audioGroup->playback_stream, "Playback");
922 if (status != B_OK) {
923 dprintf("hda: Error setting up playback buffers: %s\n",
924 strerror(status));
925 return status;
929 if (audioGroup->record_stream != NULL) {
930 audioGroup->record_stream->num_buffers = data->return_record_buffers;
931 audioGroup->record_stream->num_channels = data->return_record_channels;
932 audioGroup->record_stream->buffer_length
933 = data->return_record_buffer_size;
935 status_t status = hda_stream_setup_buffers(audioGroup,
936 audioGroup->record_stream, "Recording");
937 if (status != B_OK) {
938 dprintf("hda: Error setting up recording buffers: %s\n",
939 strerror(status));
940 return status;
944 /* Setup data structure for multi_audio API... */
946 if (audioGroup->playback_stream != NULL) {
947 uint32 playbackSampleSize = audioGroup->playback_stream->sample_size;
949 for (int32 i = 0; i < data->return_playback_buffers; i++) {
950 for (int32 channelIndex = 0;
951 channelIndex < data->return_playback_channels; channelIndex++) {
952 data->playback_buffers[i][channelIndex].base
953 = (char*)audioGroup->playback_stream->buffers[i]
954 + playbackSampleSize * channelIndex;
955 data->playback_buffers[i][channelIndex].stride
956 = playbackSampleSize * data->return_playback_channels;
961 if (audioGroup->record_stream != NULL) {
962 uint32 recordSampleSize = audioGroup->record_stream->sample_size;
964 for (int32 i = 0; i < data->return_record_buffers; i++) {
965 for (int32 channelIndex = 0;
966 channelIndex < data->return_record_channels; channelIndex++) {
967 data->record_buffers[i][channelIndex].base
968 = (char*)audioGroup->record_stream->buffers[i]
969 + recordSampleSize * channelIndex;
970 data->record_buffers[i][channelIndex].stride
971 = recordSampleSize * data->return_record_channels;
976 return B_OK;
980 /*! playback_buffer_cycle is the buffer we want to have played */
981 static status_t
982 buffer_exchange(hda_audio_group* audioGroup, multi_buffer_info* data)
984 cpu_status status;
985 status_t err;
986 multi_buffer_info buffer_info;
988 if (audioGroup->playback_stream == NULL)
989 return B_ERROR;
991 if (!audioGroup->playback_stream->running) {
992 hda_stream_start(audioGroup->codec->controller,
993 audioGroup->playback_stream);
995 if (audioGroup->record_stream && !audioGroup->record_stream->running) {
996 hda_stream_start(audioGroup->codec->controller,
997 audioGroup->record_stream);
1000 #ifdef __HAIKU__
1001 if (user_memcpy(&buffer_info, data, sizeof(buffer_info)) < B_OK)
1002 return B_BAD_ADDRESS;
1003 #else
1004 memcpy(&buffer_info, data, sizeof(buffer_info));
1005 #endif
1007 /* do playback */
1008 err = acquire_sem_etc(audioGroup->codec->controller->buffer_ready_sem,
1009 1, B_CAN_INTERRUPT, 0);
1010 if (err != B_OK) {
1011 ERROR("%s: Error waiting for playback buffer to finish (%s)!\n", __func__,
1012 strerror(err));
1013 return err;
1016 status = disable_interrupts();
1017 acquire_spinlock(&audioGroup->playback_stream->lock);
1019 buffer_info.playback_buffer_cycle
1020 = (audioGroup->playback_stream->buffer_cycle)
1021 % audioGroup->playback_stream->num_buffers;
1022 buffer_info.played_real_time = audioGroup->playback_stream->real_time;
1023 buffer_info.played_frames_count = audioGroup->playback_stream->frames_count;
1025 release_spinlock(&audioGroup->playback_stream->lock);
1027 if (audioGroup->record_stream) {
1028 acquire_spinlock(&audioGroup->record_stream->lock);
1029 buffer_info.record_buffer_cycle
1030 = (audioGroup->record_stream->buffer_cycle - 1)
1031 % audioGroup->record_stream->num_buffers;
1032 buffer_info.recorded_real_time = audioGroup->record_stream->real_time;
1033 buffer_info.recorded_frames_count
1034 = audioGroup->record_stream->frames_count;
1035 release_spinlock(&audioGroup->record_stream->lock);
1038 restore_interrupts(status);
1040 #ifdef __HAIKU__
1041 if (user_memcpy(data, &buffer_info, sizeof(buffer_info)) < B_OK)
1042 return B_BAD_ADDRESS;
1043 #else
1044 memcpy(data, &buffer_info, sizeof(buffer_info));
1045 #endif
1047 #if 0
1048 static int debugBuffersExchanged = 0;
1050 debugBuffersExchanged++;
1051 if ((debugBuffersExchanged % 100) == 1 && debugBuffersExchanged < 1111)
1052 dprintf("%s: %d buffers processed\n", __func__, debugBuffersExchanged);
1053 #endif
1054 return B_OK;
1058 static status_t
1059 buffer_force_stop(hda_audio_group* audioGroup)
1061 if (audioGroup->playback_stream != NULL) {
1062 hda_stream_stop(audioGroup->codec->controller,
1063 audioGroup->playback_stream);
1065 if (audioGroup->record_stream != NULL) {
1066 hda_stream_stop(audioGroup->codec->controller,
1067 audioGroup->record_stream);
1070 return B_OK;
1074 status_t
1075 multi_audio_control(void* cookie, uint32 op, void* arg, size_t len)
1077 hda_codec* codec = (hda_codec*)cookie;
1078 hda_audio_group* audioGroup;
1080 /* FIXME: We should simply pass the audioGroup into here... */
1081 if (!codec || codec->num_audio_groups == 0)
1082 return ENODEV;
1084 audioGroup = codec->audio_groups[0];
1086 // TODO: make userland-safe when built for Haiku!
1088 switch (op) {
1089 case B_MULTI_GET_DESCRIPTION:
1091 #ifdef __HAIKU__
1092 multi_description description;
1093 multi_channel_info channels[16];
1094 multi_channel_info* originalChannels;
1096 if (user_memcpy(&description, arg, sizeof(multi_description))
1097 != B_OK)
1098 return B_BAD_ADDRESS;
1100 originalChannels = description.channels;
1101 description.channels = channels;
1102 if (description.request_channel_count > 16)
1103 description.request_channel_count = 16;
1105 status_t status = get_description(audioGroup, &description);
1106 if (status != B_OK)
1107 return status;
1109 description.channels = originalChannels;
1110 if (user_memcpy(arg, &description, sizeof(multi_description))
1111 != B_OK)
1112 return B_BAD_ADDRESS;
1113 return user_memcpy(originalChannels, channels,
1114 sizeof(multi_channel_info) * description.request_channel_count);
1115 #else
1116 return get_description(audioGroup, (multi_description*)arg);
1117 #endif
1120 case B_MULTI_GET_ENABLED_CHANNELS:
1121 return get_enabled_channels(audioGroup, (multi_channel_enable*)arg);
1122 case B_MULTI_SET_ENABLED_CHANNELS:
1123 return B_OK;
1125 case B_MULTI_GET_GLOBAL_FORMAT:
1126 return get_global_format(audioGroup, (multi_format_info*)arg);
1127 case B_MULTI_SET_GLOBAL_FORMAT:
1128 return set_global_format(audioGroup, (multi_format_info*)arg);
1130 case B_MULTI_LIST_MIX_CHANNELS:
1131 return list_mix_channels(audioGroup, (multi_mix_channel_info*)arg);
1132 case B_MULTI_LIST_MIX_CONTROLS:
1133 return list_mix_controls(audioGroup, (multi_mix_control_info*)arg);
1134 case B_MULTI_LIST_MIX_CONNECTIONS:
1135 return list_mix_connections(audioGroup,
1136 (multi_mix_connection_info*)arg);
1137 case B_MULTI_GET_MIX:
1138 return get_mix(audioGroup, (multi_mix_value_info *)arg);
1139 case B_MULTI_SET_MIX:
1140 return set_mix(audioGroup, (multi_mix_value_info *)arg);
1142 case B_MULTI_GET_BUFFERS:
1143 return get_buffers(audioGroup, (multi_buffer_list*)arg);
1145 case B_MULTI_BUFFER_EXCHANGE:
1146 return buffer_exchange(audioGroup, (multi_buffer_info*)arg);
1147 case B_MULTI_BUFFER_FORCE_STOP:
1148 return buffer_force_stop(audioGroup);
1150 case B_MULTI_GET_EVENT_INFO:
1151 case B_MULTI_SET_EVENT_INFO:
1152 case B_MULTI_GET_EVENT:
1153 case B_MULTI_GET_CHANNEL_FORMATS:
1154 case B_MULTI_SET_CHANNEL_FORMATS:
1155 case B_MULTI_SET_BUFFERS:
1156 case B_MULTI_SET_START_TIME:
1157 return B_ERROR;
1160 return B_BAD_VALUE;