update megiaudioroute.c for 5.9 kernel

When combined with Sam's audio patch, this fixes audio calls on 5.9
kernel.

Source: https://xnux.eu/devices/feature/audio-pp.html
Signed-off-by: Anjandev Momi <anjan@momi.ca>
master
Anjandev Momi 4 years ago
parent c8ca9e850b
commit 55887d9afe
  1. 583
      programs/sxmo_megiaudioroute.c

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

Loading…
Cancel
Save