/* * example_mixer.c * The primary interface into the sample mixer. * 24 Jan 2001 * Copyright QNX Software Systems GmbH & Co. KG. All rights reserved. */ #include <example.h> #include <proto.h> static uint8_t example_mixer_read (example_t * example, uint32_t reg) { uint8_t val = 0; /* Generic code to read a mixer register and set * the variable "val" should go here. */ return val; } static void example_mixer_write (example_t * example, uint32_t reg, uint8_t val) { /* Generic code to write a mixer register with the value of * the variable "val" should go here. */ } static snd_mixer_voice_t stereo_voices[2] = { {SND_MIXER_VOICE_LEFT, 0}, {SND_MIXER_VOICE_RIGHT, 0} }; static struct snd_mixer_element_volume1_range output_range[2] = { {0, 63, -600, 1650}, {0, 63, -600, 1650} }; static struct snd_mixer_element_volume1_range input_range[2] = { {0, 15, -2850, 300}, {0, 15, -2850, 300} }; static int32_t example_master_vol_control (MIXER_CONTEXT_T * example, ado_mixer_delement_t * element, uint8_t set, uint32_t * vol, void *instance_data) { enum example_mixer_reg reg = (int32_t) instance_data; uint32_t data[2]; int32_t altered = 0; int max = ado_mixer_element_vol_range_max (element); data[0] = example_mixer_read (example, reg + 0); data[1] = example_mixer_read (example, reg + 2); if (set) { altered = vol[0] != ( data[0] & max ) || vol[1] != ( data[1] & max ); data[0] = ( data[0] & ~(max) ) | vol[0]; data[1] = ( data[1] & ~(max) ) | vol[0]; example_mixer_write (example, reg + 0, data[0]); example_mixer_write (example, reg + 2, data[1]); } else { vol[0] = (data[0] & max); vol[1] = (data[1] & max); } return (altered); } static int32_t example_master_mute_control (MIXER_CONTEXT_T * example, ado_mixer_delement_t * element, uint8_t set, uint32_t * val, void *instance_data) { enum example_mixer_reg reg = (int32_t) instance_data; uint32_t data[2]; int32_t altered = 0; data[0] = example_mixer_read (example, reg + 0); data[1] = example_mixer_read (example, reg + 2); if (set) { altered = val[0] != ( ( data[0] & 0x40 ) ? ( 1 << 0) : 0 ) | ( ( data[1] & 0x40 ) ? ( 1 << 1) : 0 ); data[0] = ( data[0] & ~0x40 ) | ( ( val[0] & (1 << 0) ) ? 0x40 : 0 ); data[1] = ( data[1] & ~0x40 ) | ( ( val[0] & (1 << 1) ) ? 0x40 : 0 ); example_mixer_write (example, reg + 0, data[0]); example_mixer_write (example, reg + 2, data[1]); } else val[0] = ( ( data[0] & 0x40 ) ? (1 << 0) : 0 ) | ( ( data[1] & 0x40 ) ? (1 << 1) : 0 ); return (altered); } static int32_t example_vol_control (MIXER_CONTEXT_T * example, ado_mixer_delement_t * element, uint8_t set, uint32_t * vol, void *instance_data) { enum example_mixer_reg reg = (int32_t) instance_data; uint32_t data; int32_t altered = 0; int max = ado_mixer_element_vol_range_max (element); data = example_mixer_read (example, reg); if (set) { altered = vol[0] != ( ( data & (max << 8) ) >> 8 ) || vol[1] != (data & max); data = (data & ~( (max << 4) | max) ) | ( (vol[0]) << 4) | (vol[1]); example_mixer_write (example, reg, data); } else { vol[0] = ( (data & (max << 4) ) >> 4); vol[1] = ( (data & max) ); } return (altered); } int build_in_group( MIXER_CONTEXT_T * example, char *name_p, char *name_c, example_group * grp, enum example_mixer_reg reg_p, enum example_mixer_reg reg_c) { int error = 0; ado_mixer_delement_t *pre_elem, *elem = NULL; char ename[sizeof (((snd_mixer_eid_t *) 0)->name)]; if ( grp == &example->pcm ) { if ( !error && (elem = ado_mixer_element_io (example->mixer, name_p, SND_MIXER_ETYPE_PLAYBACK1, 0, 2, stereo_voices)) == NULL ) error++; } else { if ( !error && (elem = ado_mixer_element_io (example->mixer, name_p, SND_MIXER_ETYPE_INPUT, 0, 2, stereo_voices)) == NULL ) error++; } pre_elem = elem; sprintf (ename, "%s %s", name_p, "Volume"); if ( !error && (elem = ado_mixer_element_volume1 (example->mixer, ename, 2, input_range, example_vol_control, (void *) reg_p, NULL)) == NULL ) error++; if ( !error && ado_mixer_element_route_add (example->mixer, pre_elem, elem) != 0 ) error++; grp->vol_out = elem; if ( !error && ado_mixer_element_route_add (example->mixer, elem, example->output_accu) != 0 ) error++; if (name_c) { if ( !error && ado_mixer_element_route_add (example->mixer, pre_elem, example->input_accu) != 0 ) error++; } if ( !error && name_p && (grp->group_p = ado_mixer_playback_group_create (example->mixer, name_p, SND_MIXER_CHN_MASK_STEREO, grp->vol_out, NULL)) == NULL ) error++; if ( !error && name_c && (grp->group_c = ado_mixer_capture_group_create (example->mixer, name_c, SND_MIXER_CHN_MASK_STEREO, NULL, NULL, NULL, NULL)) == NULL ) error++; return (0); } int build_example_mixer (MIXER_CONTEXT_T * example, ado_mixer_t * mixer) { int error = 0; ado_mixer_delement_t *pre_elem, *elem = NULL; /* ################ */ /* the OUTPUT GROUP */ /* ################ */ if ((example->output_accu = ado_mixer_element_accu1 (mixer, SND_MIXER_ELEMENT_OUTPUT_ACCU, 0)) == NULL) error++; pre_elem = example->output_accu; if ( !error && (elem = ado_mixer_element_volume1 (mixer, "Output Volume", 2, output_range, example_master_vol_control, (void *) EXAMPLE_MASTER_LEFT, NULL)) == NULL ) error++; if ( !error && ado_mixer_element_route_add (mixer, pre_elem, elem) != 0 ) error++; example->master_vol = elem; pre_elem = elem; if ( !error && (elem = ado_mixer_element_sw2 (mixer, "Output Mute", example_master_mute_control, (void *) EXAMPLE_MASTER_LEFT, NULL)) == NULL ) error++; if ( !error && ado_mixer_element_route_add (mixer, pre_elem, elem) != 0 ) error++; example->master_mute = elem; pre_elem = elem; if ( !error && (elem = ado_mixer_element_io (mixer, "Output", SND_MIXER_ETYPE_OUTPUT, 0, 2, stereo_voices)) == NULL ) error++; if ( !error && ado_mixer_element_route_add (mixer, pre_elem, elem) != 0 ) error++; if ( !error && (example->master_grp = ado_mixer_playback_group_create (mixer, SND_MIXER_MASTER_OUT, SND_MIXER_CHN_MASK_STEREO, example->master_vol, example->master_mute)) == NULL ) error++; /* ############### */ /* the INPUT GROUP */ /* ############### */ if ( (example->input_accu = ado_mixer_element_accu1 (mixer, SND_MIXER_ELEMENT_INPUT_ACCU, 0)) == NULL ) error++; pre_elem = example->input_accu; if ( !error && (elem = ado_mixer_element_volume1 (mixer, "Input Volume", 2, input_range, example_vol_control, (void *) EXAMPLE_RECORD_LEVEL, NULL)) == NULL ) error++; if ( !error && ado_mixer_element_route_add (mixer, pre_elem, elem) != 0 ) error++; example->master_vol = elem; pre_elem = elem; if ( !error && (elem = ado_mixer_element_io (mixer, SND_MIXER_ELEMENT_CAPTURE, SND_MIXER_ETYPE_CAPTURE1, 0, 2, stereo_voices)) == NULL ) error++; if ( !error && ado_mixer_element_route_add (mixer, pre_elem, elem) != 0 ) error++; if ( !error && (example->input_grp = ado_mixer_capture_group_create (mixer, SND_MIXER_GRP_IGAIN, SND_MIXER_CHN_MASK_STEREO, example->master_vol, NULL, NULL, NULL)) == NULL ) error++; /* ################ */ /* the INPUT GROUPS */ /* ################ */ if ( !error && build_in_group (example, SND_MIXER_PCM_OUT, NULL, &example->pcm, EXAMPLE_PCM_OUT_VOL, NULL) != 0 ) error++; if ( !error && build_in_group (example, SND_MIXER_MIC_OUT, SND_MIXER_MIC_IN, &example->mic, EXAMPLE_MIC_OUT_VOL, EXAMPLE_MIC_IN_VOL) != 0 ) error++; if ( !error && build_in_group (example, SND_MIXER_CD_OUT, SND_MIXER_CD_IN, &example->cd, EXAMPLE_CD_OUT_VOL, EXAMPLE_CD_IN_VOL) != 0 ) error++; return (0); } ado_mixer_reset_t example_reset; int example_reset (MIXER_CONTEXT_T * example) { /* This function, if included, should restore the mixer to a default state */ example_mixer_write( example, EXAMPLE_PCM_OUT_VOL, 0xff ); /* set PCM vol 100% */ example_mixer_write( example, EXAMPLE_CD_OUT_VOL, 0xff ); /* set cd vol 100% */ example_mixer_write( example, EXAMPLE_REC_SEL, 0x05 ); /* set record src to mixer */ return (0); } ado_mixer_destroy_t example_destroy; int example_destroy (MIXER_CONTEXT_T * example) { /* This function, if included, should set the mixer to a safe state */ example_mixer_write( example, EXAMPLE_PCM_OUT_VOL, 0x0 ); /* set PCM vol 0% */ example_mixer_write( example, EXAMPLE_CD_OUT_VOL, 0x00 ); /* set cd vol 0% */ return (0); } int example_mixer (ado_card_t * card, HW_CONTEXT_T * example) { int32_t status; if ( (status = ado_mixer_create (card, "Example", &example->mixer, example)) != EOK ) return (status); example_mixer_write (example, 0x00, 0x00); /* reset the mixer */ if ( build_example_mixer (example, example->mixer) ) return (-1); if ( example_reset (example) ) return (-1); /* The following functions are optional, but if you have actions * that should be performed by the hardware whenever the mixer is * reset or destroyed. These functions are specifically for * hardware specific requirements. */ ado_mixer_set_reset_func( example->mixer, example_reset ); ado_mixer_set_destroy_func( example->mixer, example_destroy ); return (0); }