diff --git a/programs/sxmo_megiaudioroute.c b/programs/sxmo_megiaudioroute.c index 4edd0d8..4a67507 100644 --- a/programs/sxmo_megiaudioroute.c +++ b/programs/sxmo_megiaudioroute.c @@ -15,6 +15,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * 2020-09-29: Updated for the new Samuel's digital codec driver */ #include @@ -37,361 +39,348 @@ void syscall_error(int is_err, const char* fmt, ...) { - va_list ap; + va_list ap; - if (!is_err) - return; + if (!is_err) + return; - printf("ERROR: "); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf(": %s\n", strerror(errno)); + printf("ERROR: "); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf(": %s\n", strerror(errno)); - exit(1); + exit(1); } void error(const char* fmt, ...) { - va_list ap; + va_list ap; - printf("ERROR: "); - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); + printf("ERROR: "); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); - exit(1); + exit(1); } struct audio_control_state { - char name[128]; - union { - int64_t i[4]; - const char* e[4]; - } vals; - bool used; + char name[128]; + union { + int64_t i[4]; + const char* e[4]; + } vals; + bool used; }; static bool audio_restore_state(struct audio_control_state* controls, int n_controls) { - int fd; - int ret; - - fd = open("/dev/snd/controlC0", O_CLOEXEC | O_NONBLOCK); - if (fd < 0) - error("failed to open card\n"); - - struct snd_ctl_elem_list el = { - .offset = 0, - .space = 0, - }; - ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &el); - syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_LIST failed"); - - struct snd_ctl_elem_id ids[el.count]; - el.pids = ids; - el.space = el.count; - ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &el); - syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_LIST failed"); - - for (int i = 0; i < el.used; i++) { - struct snd_ctl_elem_info inf = { - .id = ids[i], - }; - - ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &inf); - syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_INFO failed"); - - if ((inf.access & SNDRV_CTL_ELEM_ACCESS_READ) && (inf.access & SNDRV_CTL_ELEM_ACCESS_WRITE)) { - struct snd_ctl_elem_value val = { - .id = ids[i], - }; - int64_t cval = 0; - - ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_READ, &val); - syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_READ failed"); - - struct audio_control_state* cs = NULL; - for (int j = 0; j < n_controls; j++) { - if (!strcmp(controls[j].name, ids[i].name)) { - cs = &controls[j]; - break; - } - } - - if (!cs) { - printf("Control \"%s\" si not defined in the controls state\n", ids[i].name); - continue; - } - - cs->used = 1; - - // check if value needs changing - - switch (inf.type) { - case SNDRV_CTL_ELEM_TYPE_BOOLEAN: - case SNDRV_CTL_ELEM_TYPE_INTEGER: - for (int j = 0; j < inf.count; j++) { - if (cs->vals.i[j] != val.value.integer.value[j]) { - // update - //printf("%s <=[%d]= %"PRIi64"\n", ids[i].name, j, cs->vals.i[j]); - - val.value.integer.value[j] = cs->vals.i[j]; - ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &val); - syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_WRITE failed"); - } - } - - break; - case SNDRV_CTL_ELEM_TYPE_INTEGER64: - for (int j = 0; j < inf.count; j++) { - if (cs->vals.i[j] != val.value.integer64.value[j]) { - // update - //printf("%s <=[%d]= %"PRIi64"\n", ids[i].name, j, cs->vals.i[j]); - - val.value.integer64.value[j] = cs->vals.i[j]; - ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &val); - syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_WRITE failed"); - } - } - - break; - - case SNDRV_CTL_ELEM_TYPE_ENUMERATED: { - for (int k = 0; k < inf.count; k++) { - int eval = -1; - for (int j = 0; j < inf.value.enumerated.items; j++) { - inf.value.enumerated.item = j; - - ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &inf); - syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_INFO failed"); - - if (!strcmp(cs->vals.e[k], inf.value.enumerated.name)) { - eval = j; - break; - } - } - - if (eval < 0) - error("enum value %s not found\n", cs->vals.e[k]); - - if (eval != val.value.enumerated.item[k]) { - // update - //printf("%s <=%d= %s\n", ids[i].name, k, cs->vals.e[k]); - - val.value.enumerated.item[k] = eval; - ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &val); - syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_WRITE failed"); - } - } - - break; - } - } - } - } - - for (int j = 0; j < n_controls; j++) - if (!controls[j].used) - printf("Control \"%s\" is defined in state but not present on the card\n", controls[j].name); - - close(fd); - return true; + int fd; + int ret; + + fd = open("/dev/snd/controlC0", O_CLOEXEC | O_NONBLOCK); + if (fd < 0) + error("failed to open card\n"); + + struct snd_ctl_elem_list el = { + .offset = 0, + .space = 0, + }; + ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &el); + syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_LIST failed"); + + struct snd_ctl_elem_id ids[el.count]; + el.pids = ids; + el.space = el.count; + ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &el); + syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_LIST failed"); + + for (int i = 0; i < el.used; i++) { + struct snd_ctl_elem_info inf = { + .id = ids[i], + }; + + ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &inf); + syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_INFO failed"); + + if ((inf.access & SNDRV_CTL_ELEM_ACCESS_READ) && (inf.access & SNDRV_CTL_ELEM_ACCESS_WRITE)) { + struct snd_ctl_elem_value val = { + .id = ids[i], + }; + int64_t cval = 0; + + ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_READ, &val); + syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_READ failed"); + + struct audio_control_state* cs = NULL; + for (int j = 0; j < n_controls; j++) { + if (!strcmp(controls[j].name, ids[i].name)) { + cs = &controls[j]; + break; + } + } + + if (!cs) { + printf("Control \"%s\" si not defined in the controls state\n", ids[i].name); + continue; + } + + cs->used = 1; + + // check if value needs changing + + switch (inf.type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + case SNDRV_CTL_ELEM_TYPE_INTEGER: + for (int j = 0; j < inf.count; j++) { + if (cs->vals.i[j] != val.value.integer.value[j]) { + // update + //printf("%s <=[%d]= %"PRIi64"\n", ids[i].name, j, cs->vals.i[j]); + + val.value.integer.value[j] = cs->vals.i[j]; + ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &val); + syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_WRITE failed"); + } + } + + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + for (int j = 0; j < inf.count; j++) { + if (cs->vals.i[j] != val.value.integer64.value[j]) { + // update + //printf("%s <=[%d]= %"PRIi64"\n", ids[i].name, j, cs->vals.i[j]); + + val.value.integer64.value[j] = cs->vals.i[j]; + ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &val); + syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_WRITE failed"); + } + } + + break; + + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: { + for (int k = 0; k < inf.count; k++) { + int eval = -1; + for (int j = 0; j < inf.value.enumerated.items; j++) { + inf.value.enumerated.item = j; + + ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &inf); + syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_INFO failed"); + + if (!strcmp(cs->vals.e[k], inf.value.enumerated.name)) { + eval = j; + break; + } + } + + if (eval < 0) + error("enum value %s not found\n", cs->vals.e[k]); + + if (eval != val.value.enumerated.item[k]) { + // update + //printf("%s <=%d= %s\n", ids[i].name, k, cs->vals.e[k]); + + val.value.enumerated.item[k] = eval; + ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &val); + syscall_error(ret < 0, "SNDRV_CTL_IOCTL_ELEM_WRITE failed"); + } + } + + break; + } + } + } + } + + for (int j = 0; j < n_controls; j++) + if (!controls[j].used) + printf("Control \"%s\" is defined in state but not present on the card\n", controls[j].name); + + close(fd); + return true; } struct audio_setup { - bool mic_on; - bool spk_on; - bool hp_on; - bool ear_on; - bool hpmic_on; - - // when sending audio to modem from AIF1 R, also play that back - // to me locally (just like AIF1 L plays just to me) - // - // this is to monitor what SW is playing to the modem (so that - // I can hear my robocaller talking) - bool modem_playback_monitor; - - // enable modem routes to DAC/from ADC (spk/mic) - // digital paths to AIF1 are always on - bool to_modem_on; - bool from_modem_on; - - // shut off/enable all digital paths to the modem: - // keep this off until the call starts, then turn it on - bool dai2_en; - - int mic_gain; - int hpmic_gain; - int spk_vol; - int ear_vol; - int hp_vol; + bool mic_on; + bool spk_on; + bool hp_on; + bool ear_on; + + // when sending audio to modem from AIF1 R, also play that back + // to me locally (just like AIF1 L plays just to me) + // + // this is to monitor what SW is playing to the modem (so that + // I can hear my robocaller talking) + bool modem_playback_monitor; + + // enable modem routes to DAC/from ADC (spk/mic) + // digital paths to AIF1 are always on + bool to_modem_on; + bool from_modem_on; + + // shut off/enable all digital paths to the modem: + // keep this off until the call starts, then turn it on + bool dai2_en; + + int mic_gain; + int spk_vol; + int ear_vol; + int hp_vol; }; static void audio_set_controls(struct audio_setup* s) { - struct audio_control_state controls[] = { - // + struct audio_control_state controls[] = { + // // Analog input: - // + // - // Mic 1 (daughterboard) - { .name = "Mic1 Boost Volume", .vals.i = { s->mic_gain } }, + // Mic 1 (daughterboard) + { .name = "Mic1 Boost Volume", .vals.i = { s->mic_gain } }, - // Mic 2 (headphones) - { .name = "Mic2 Boost Volume", .vals.i = { s->hpmic_gain } }, + // Mic 2 (headphones) + { .name = "Mic2 Boost Volume", .vals.i = { 0 } }, - // Line in (unused on PP) - // no controls yet + // Line in (unused on PP) + // no controls yet // Input mixers before ADC - { .name = "Mic1 Capture Switch", .vals.i = { !!s->mic_on, !!s->mic_on } }, - { .name = "Mic2 Capture Switch", .vals.i = { !!s->hpmic_on, !!s->hpmic_on } }, - { .name = "Line In Capture Switch", .vals.i = { 0, 0 } }, // Out Mix -> In Mix - { .name = "Mixer Capture Switch", .vals.i = { 0, 0 } }, - { .name = "Mixer Reversed Capture Switch", .vals.i = { 0, 0 } }, + { .name = "Mic1 Capture Switch", .vals.i = { !!s->mic_on, !!s->mic_on } }, + { .name = "Mic2 Capture Switch", .vals.i = { 0, 0 } }, + { .name = "Line In Capture Switch", .vals.i = { 0, 0 } }, // Out Mix -> In Mix + { .name = "Mixer Capture Switch", .vals.i = { 0, 0 } }, + { .name = "Mixer Reversed Capture Switch", .vals.i = { 0, 0 } }, - // ADC - { .name = "ADC Gain Capture Volume", .vals.i = { 0 } }, - { .name = "ADC Capture Volume", .vals.i = { 160, 160 } }, // digital gain + // ADC + { .name = "ADC Gain Capture Volume", .vals.i = { 0 } }, + { .name = "ADC Capture Volume", .vals.i = { 160, 160 } }, // digital gain - // + // // Digital paths: - // + // - // AIF1 (SoC) + // AIF1 (SoC) - // AIF1 slot0 capture mixer sources - { .name = "AIF1 AD0 Mixer ADC Capture Switch", .vals.i = { 1, 0 } }, - { .name = "AIF1 AD0 Mixer AIF1 DA0 Capture Switch", .vals.i = { 0, 0 } }, - { .name = "AIF1 AD0 Mixer AIF2 DAC Capture Switch", .vals.i = { 0, 1 } }, - { .name = "AIF1 AD0 Mixer AIF2 DAC Rev Capture Switch", .vals.i = { 0, 0 } }, //XXX: capture right from the left AIF2? - { .name = "AIF1 Loopback Switch", .vals.i = { 0 } }, + // AIF1 slot0 capture mixer sources + { .name = "AIF1 Data Digital ADC Capture Switch", .vals.i = { 1, 0 } }, + { .name = "AIF1 Slot 0 Digital ADC Capture Switch", .vals.i = { 0, 0 } }, + { .name = "AIF2 Digital ADC Capture Switch", .vals.i = { 0, 1 } }, + { .name = "AIF2 Inv Digital ADC Capture Switch", .vals.i = { 0, 0 } }, //XXX: capture right from the left AIF2? - // AIF1 slot0 capture/playback mono mixing/digital volume - { .name = "AIF1 AD0 Capture Volume", .vals.i = { 160, 160 } }, - { .name = "AIF1 AD0 Stereo Capture Route", .vals.e = { "Stereo", "Stereo" } }, - { .name = "AIF1 DA0 Playback Volume", .vals.i = { 160, 160 } }, - { .name = "AIF1 DA0 Stereo Playback Route", .vals.e = { "Stereo", "Stereo" } }, + // AIF1 slot0 capture/playback mono mixing/digital volume + { .name = "AIF1 AD0 Capture Volume", .vals.i = { 160, 160 } }, + { .name = "AIF1 AD0 Stereo Capture Route", .vals.e = { "Stereo", "Stereo" } }, + { .name = "AIF1 DA0 Playback Volume", .vals.i = { 160, 160 } }, + { .name = "AIF1 DA0 Stereo Playback Route", .vals.e = { "Stereo", "Stereo" } }, - // AIF2 (modem) + // AIF2 (modem) - // AIF2 capture mixer sources - { .name = "AIF2 ADC Mixer ADC Capture Switch", .vals.i = { !!s->to_modem_on && !!s->dai2_en, 0 } }, // from adc/mic - { .name = "AIF2 ADC Mixer AIF1 DA0 Capture Switch", .vals.i = { 0, 1 } }, // from aif1 R - { .name = "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", .vals.i = { 0, 0 } }, - { .name = "AIF2 Loopback Switch", .vals.i = { 0 } }, + // AIF2 capture mixer sources + { .name = "AIF2 ADC Mixer ADC Capture Switch", .vals.i = { !!s->to_modem_on && !!s->dai2_en, 0 } }, // from adc/mic + { .name = "AIF2 ADC Mixer AIF1 DA0 Capture Switch", .vals.i = { 0, 1 } }, // from aif1 R + { .name = "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", .vals.i = { 0, 0 } }, - // AIF2 capture/playback mono mixing/digital volume - { .name = "AIF2 ADC Capture Volume", .vals.i = { 160, 160 } }, - { .name = "AIF2 DAC Playback Volume", .vals.i = { 160, 160 } }, - { .name = "AIF2 ADC Stereo Capture Route", .vals.e = { "Mix Mono", "Mix Mono" } }, // we mix because we're sending two channels (from mic and AIF1 R) - { .name = "AIF2 DAC Stereo Playback Route", .vals.e = { "Sum Mono", "Sum Mono" } }, // we sum because modem is sending a single channel + // AIF2 capture/playback mono mixing/digital volume + { .name = "AIF2 ADC Capture Volume", .vals.i = { 160, 160 } }, + { .name = "AIF2 DAC Playback Volume", .vals.i = { 160, 160 } }, + { .name = "AIF2 ADC Stereo Capture Route", .vals.e = { "Mix Mono", "Mix Mono" } }, // we mix because we're sending two channels (from mic and AIF1 R) + { .name = "AIF2 DAC Stereo Playback Route", .vals.e = { "Sum Mono", "Sum Mono" } }, // we sum because modem is sending a single channel // AIF3 (bluetooth) - { .name = "AIF3 Loopback Switch", .vals.i = { 0 } }, - { .name = "AIF3 ADC Capture Route", .vals.e = { "None" } }, - { .name = "AIF3 DAC Playback Route", .vals.e = { "None" } }, + { .name = "AIF3 ADC Source Capture Route", .vals.e = { "None" } }, + { .name = "AIF2 DAC Source Playback Route", .vals.e = { "AIF2" } }, - // DAC + // DAC - // DAC input mixers (sources from ADC, and AIF1/2) - { .name = "DAC Mixer ADC Playback Switch", .vals.i = { 0, 0 } }, // we don't play our mic to ourselves - { .name = "DAC Mixer AIF1 DA0 Playback Switch", .vals.i = { 1, !!s->modem_playback_monitor } }, - { .name = "DAC Mixer AIF2 DAC Playback Switch", .vals.i = { 0, !!s->dai2_en && !!s->from_modem_on } }, + // DAC input mixers (sources from ADC, and AIF1/2) + { .name = "ADC Digital DAC Playback Switch", .vals.i = { 0, 0 } }, // we don't play our mic to ourselves + { .name = "AIF1 Slot 0 Digital DAC Playback Switch", .vals.i = { 1, !!s->modem_playback_monitor } }, + { .name = "AIF2 Digital DAC Playback Switch", .vals.i = { 0, !!s->dai2_en && !!s->from_modem_on } }, - // - // Analog output: - // + // + // Analog output: + // - // Output mixer after DAC + // Output mixer after DAC - { .name = "DAC Playback Switch", .vals.i = { 1, 1 } }, - { .name = "DAC Reversed Playback Switch", .vals.i = { 1, 1 } }, - { .name = "DAC Playback Volume", .vals.i = { 160, 160 } }, - { .name = "Mic1 Playback Switch", .vals.i = { 0, 0 } }, - { .name = "Mic1 Playback Volume", .vals.i = { 0 } }, - { .name = "Mic2 Playback Switch", .vals.i = { 0, 0 } }, - { .name = "Mic2 Playback Volume", .vals.i = { 0 } }, - { .name = "Line In Playback Switch", .vals.i = { 0, 0 } }, - { .name = "Line In Playback Volume", .vals.i = { 0 } }, + { .name = "DAC Playback Switch", .vals.i = { 1, 1 } }, + { .name = "DAC Reversed Playback Switch", .vals.i = { 1, 1 } }, + { .name = "DAC Playback Volume", .vals.i = { 160, 160 } }, + { .name = "Mic1 Playback Switch", .vals.i = { 0, 0 } }, + { .name = "Mic1 Playback Volume", .vals.i = { 0 } }, + { .name = "Mic2 Playback Switch", .vals.i = { 0, 0 } }, + { .name = "Mic2 Playback Volume", .vals.i = { 0 } }, + { .name = "Line In Playback Switch", .vals.i = { 0, 0 } }, + { .name = "Line In Playback Volume", .vals.i = { 0 } }, // Outputs - { .name = "Earpiece Source Playback Route", .vals.e = { "Left Mixer" } }, - { .name = "Earpiece Playback Switch", .vals.i = { !!s->ear_on } }, - { .name = "Earpiece Playback Volume", .vals.i = { s->ear_vol } }, + { .name = "Earpiece Source Playback Route", .vals.e = { "Left Mixer" } }, + { .name = "Earpiece Playback Switch", .vals.i = { !!s->ear_on } }, + { .name = "Earpiece Playback Volume", .vals.i = { s->ear_vol } }, - { .name = "Headphone Source Playback Route", .vals.e = { "Mixer", "Mixer" } }, - { .name = "Headphone Playback Switch", .vals.i = { !!s->hp_on, !!s->hp_on } }, - { .name = "Headphone Playback Volume", .vals.i = { s->hp_vol } }, + { .name = "Headphone Source Playback Route", .vals.e = { "Mixer", "Mixer" } }, + { .name = "Headphone Playback Switch", .vals.i = { !!s->hp_on, !!s->hp_on } }, + { .name = "Headphone Playback Volume", .vals.i = { s->hp_vol } }, - // Loudspeaker - { .name = "Line Out Source Playback Route", .vals.e = { "Mono Differential", "Mono Differential" } }, - { .name = "Line Out Playback Switch", .vals.i = { !!s->spk_on, !!s->spk_on } }, - { .name = "Line Out Playback Volume", .vals.i = { s->spk_vol } }, - }; + // Loudspeaker + { .name = "Line Out Source Playback Route", .vals.e = { "Mono Differential", "Mono Differential" } }, + { .name = "Line Out Playback Switch", .vals.i = { !!s->spk_on, !!s->spk_on } }, + { .name = "Line Out Playback Volume", .vals.i = { s->spk_vol } }, + }; - audio_restore_state(controls, ARRAY_SIZE(controls)); + audio_restore_state(controls, ARRAY_SIZE(controls)); } static struct audio_setup audio_setup = { - .mic_on = false, - .ear_on = false, - .spk_on = false, - .hp_on = false, - - .from_modem_on = true, - .to_modem_on = true, - .modem_playback_monitor = false, - - .dai2_en = false, - - .hp_vol = 25, - .spk_vol = 25, - .ear_vol = 25, - .mic_gain = 1, - .hpmic_gain = 1, + .mic_on = true, + .ear_on = true, + .spk_on = false, + .hp_on = false, + + .from_modem_on = true, + .to_modem_on = true, + .modem_playback_monitor = false, + + .dai2_en = false, + + .hp_vol = 15, + .spk_vol = 15, + .ear_vol = 31, + .mic_gain = 1, }; int main(int ac, char* av[]) { - int opt; - - while ((opt = getopt(ac, av, "smhlez2")) != -1) { - switch (opt) { - case 's': - audio_setup.spk_on = 1; - break; - case 'm': - audio_setup.mic_on = 1; - break; - case 'h': - audio_setup.hp_on = 1; - break; - case 'l': - audio_setup.hpmic_on = 1; - break; - case 'e': - audio_setup.ear_on = 1; - break; - case 'z': - audio_setup.modem_playback_monitor = 1; - break; - case '2': - audio_setup.dai2_en = 1; - break; - default: /* '?' */ - fprintf(stderr, "Usage: %s [-s] [-m] [-h] [-l] [-e] [-2] [-z]\n", av[0]); - exit(EXIT_FAILURE); - } - } - - audio_set_controls(&audio_setup); - return 0; + int opt; + + while ((opt = getopt(ac, av, "smhe2")) != -1) { + switch (opt) { + case 's': + audio_setup.spk_on = 1; + break; + case 'm': + audio_setup.mic_on = 1; + break; + case 'h': + audio_setup.hp_on = 1; + break; + case 'e': + audio_setup.ear_on = 1; + break; + case '2': + audio_setup.dai2_en = 1; + break; + default: /* '?' */ + fprintf(stderr, "Usage: %s [-s] [-m] [-h] [-e] [-2]\n", av[0]); + exit(EXIT_FAILURE); + } + } + + audio_set_controls(&audio_setup); + return 0; } -