alsa-utils/iecset/iecset.c
Diego E. 'Flameeyes' Pettenò 6232f1c96c Make some static tables and strings constants.
By doing this we move them from the .data section to .rodata setion,
or from .data.rel to .data.rel.ro.

The .rodata section is mapped directly from the on-disk file, which is
always a save, while .data.rel.ro is mapped directly when using
prelink, which is a save in a lot of cases.

Signed-off-by: Diego E. 'Flameeyes' Pettenò <flameeyes@gmail.com>
2008-11-21 13:10:02 +01:00

432 lines
11 KiB
C

/*
iecset - change IEC958 status bits on ALSA
Copyright (C) 2003 by Takashi Iwai <tiwai@suse.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <ctype.h>
#include <alsa/asoundlib.h>
void dump_iec958(snd_aes_iec958_t *iec);
static int get_bool(const char *str)
{
if (strncmp(str, "yes", 3) == 0 ||
strncmp(str, "YES", 3) == 0 ||
strncmp(str, "on", 2) == 0 ||
strncmp(str, "ON", 2) == 0 ||
strncmp(str, "true", 4) == 0 ||
strncmp(str, "TRUE", 4) == 0 ||
*str == '1')
return 1;
return 0;
}
enum {
CMD_BOOL, CMD_BOOL_INV, CMD_INT
};
enum {
IDX_PRO, IDX_NOAUDIO, IDX_RATE, IDX_UNLOCK, IDX_SBITS, IDX_WORD, IDX_EMP, IDX_CAT, IDX_NOCOPY, IDX_ORIG,
IDX_LAST
};
struct cmdtbl {
const char *name;
int idx;
int type;
const char *desc;
};
static const struct cmdtbl cmds[] = {
{ "pro", IDX_PRO, CMD_BOOL,
"professional (common)\n\toff = consumer mode, on = professional mode" },
{ "aud", IDX_NOAUDIO, CMD_BOOL_INV,
"audio (common)\n\ton = audio mode, off = non-audio mode" },
{ "rat", IDX_RATE, CMD_INT,
"rate (common)\n\tsample rate in Hz (0 = not indicated)" },
{ "emp", IDX_EMP, CMD_INT,
"emphasis (common)\n\t0 = none, 1 = 50/15us, 2 = CCITT" },
{ "loc", IDX_UNLOCK, CMD_BOOL_INV,
"lock (prof.)\n\toff = rate unlocked, on = rate locked" },
{ "sbi", IDX_SBITS, CMD_INT,
"sbits (prof.)\n\tsample bits 2 = 20bit, 4 = 24bit, 6 = undef" },
{ "wor", IDX_WORD, CMD_INT,
"wordlength (prof.)\n\t0=no, 2=22-18bit, 4=23-19bit, 5=24-20bit, 6=20-16bit" },
{ "cat", IDX_CAT, CMD_INT,
"category (consumer)\n\t0-0x7f" },
{ "cop", IDX_NOCOPY, CMD_BOOL_INV,
"copyright (consumer)\n\toff = non-copyright, on = copyright" },
{ "ori", IDX_ORIG, CMD_BOOL,
"original (consumer)\n\toff = 1st-gen, on = original" },
};
static void error(const char *s, int err)
{
fprintf(stderr, "%s: %s\n", s, snd_strerror(err));
}
static void usage(void)
{
int i;
printf("Usage: iecset [options] [cmd arg...]\n");
printf("Options:\n");
printf(" -D device specifies the control device to use\n");
printf(" -c card specifies the card number to use (equiv. with -Dhw:#)\n");
printf(" -n number specifies the control index number (default = 0)\n");
printf(" -x dump the dump the AESx hex code for IEC958 PCM parameters\n");
printf(" -i read commands from stdin\n");
printf("Commands:\n");
for (i = 0; i < (int)(sizeof(cmds)/sizeof(cmds[0])); i++) {
printf(" %s\n", cmds[i].desc);
}
}
/*
* parse iecset commands
*/
static void parse_command(int *parms, const char *c, const char *arg)
{
int i;
for (i = 0; i < (int)(sizeof(cmds)/sizeof(cmds[0])); i++) {
if (strncmp(c, cmds[i].name, strlen(cmds[i].name)) == 0) {
int val;
switch (cmds[i].type) {
case CMD_BOOL:
val = get_bool(arg);
break;
case CMD_BOOL_INV:
val = !get_bool(arg);
break;
case CMD_INT:
default:
val = (int)strtol(arg, NULL, 0);
break;
}
parms[cmds[i].idx] = val;
return;
}
}
}
static char *skipspace(char *line)
{
char *p;
for (p = line; *p && isspace(*p); p++)
;
return p;
}
/*
* parse iecset commands from the file
*/
static void parse_file(int *parms, FILE *fp)
{
char line[1024], *cmd, *arg;
while (fgets(line, sizeof(line), fp) != NULL) {
cmd = skipspace(line);
if (*cmd == '#' || ! *cmd)
continue;
for (arg = cmd; *arg && !isspace(*arg); arg++)
;
if (! *arg)
continue;
*arg++ = 0;
arg = skipspace(arg);
if (! *arg)
continue;
parse_command(parms, cmd, arg);
}
}
/* update iec958 status values
* return non-zero if the values are modified
*/
static int update_iec958_status(snd_aes_iec958_t *iec958, int *parms)
{
int changed = 0;
if (parms[IDX_PRO] >= 0) {
if (parms[IDX_PRO])
iec958->status[0] |= IEC958_AES0_PROFESSIONAL;
else
iec958->status[0] &= ~IEC958_AES0_PROFESSIONAL;
changed = 1;
}
if (parms[IDX_NOAUDIO] >= 0) {
if (parms[IDX_NOAUDIO])
iec958->status[0] |= IEC958_AES0_NONAUDIO;
else
iec958->status[0] &= ~IEC958_AES0_NONAUDIO;
changed = 1;
}
if (parms[IDX_RATE] >= 0) {
if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
iec958->status[0] &= ~IEC958_AES0_PRO_FS;
switch (parms[IDX_RATE]) {
case 44100:
iec958->status[0] |= IEC958_AES0_PRO_FS_44100;
break;
case 48000:
iec958->status[0] |= IEC958_AES0_PRO_FS_48000;
break;
case 32000:
iec958->status[0] |= IEC958_AES0_PRO_FS_32000;
break;
}
} else {
iec958->status[3] &= ~IEC958_AES3_CON_FS;
switch (parms[IDX_RATE]) {
case 22050:
iec958->status[3] |= IEC958_AES3_CON_FS_22050;
break;
case 24000:
iec958->status[3] |= IEC958_AES3_CON_FS_24000;
break;
case 32000:
iec958->status[3] |= IEC958_AES3_CON_FS_32000;
break;
case 44100:
iec958->status[3] |= IEC958_AES3_CON_FS_44100;
break;
case 48000:
iec958->status[3] |= IEC958_AES3_CON_FS_48000;
break;
case 88200:
iec958->status[3] |= IEC958_AES3_CON_FS_88200;;
break;
case 96000:
iec958->status[3] |= IEC958_AES3_CON_FS_96000;
break;
case 176400:
iec958->status[3] |= IEC958_AES3_CON_FS_176400;
break;
case 192000:
iec958->status[3] |= IEC958_AES3_CON_FS_192000;
break;
case 768000:
iec958->status[3] |= IEC958_AES3_CON_FS_768000;
break;
default:
iec958->status[3] |= IEC958_AES3_CON_FS_NOTID;
break;
}
}
changed = 1;
}
if (parms[IDX_NOCOPY] >= 0) {
if (! (iec958->status[0] & IEC958_AES0_PROFESSIONAL)) {
if (parms[IDX_NOCOPY])
iec958->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
else
iec958->status[0] &= ~IEC958_AES0_CON_NOT_COPYRIGHT;
}
changed = 1;
}
if (parms[IDX_ORIG] >= 0) {
if (! (iec958->status[0] & IEC958_AES0_PROFESSIONAL)) {
if (parms[IDX_ORIG])
iec958->status[1] |= IEC958_AES1_CON_ORIGINAL;
else
iec958->status[1] &= ~IEC958_AES1_CON_ORIGINAL;
}
changed = 1;
}
if (parms[IDX_EMP] >= 0) {
if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
iec958->status[0] &= ~IEC958_AES0_PRO_EMPHASIS;
switch (parms[IDX_EMP]) {
case 0:
iec958->status[0] |= IEC958_AES0_PRO_EMPHASIS_NONE;
break;
case 1:
iec958->status[0] |= IEC958_AES0_PRO_EMPHASIS_5015;
break;
case 2:
iec958->status[0] |= IEC958_AES0_PRO_EMPHASIS_CCITT;
break;
}
} else {
if (parms[IDX_EMP])
iec958->status[0] |= IEC958_AES0_CON_EMPHASIS_5015;
else
iec958->status[0] &= ~IEC958_AES0_CON_EMPHASIS_5015;
}
changed = 1;
}
if (parms[IDX_UNLOCK] >= 0) {
if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
if (parms[IDX_UNLOCK])
iec958->status[0] |= IEC958_AES0_PRO_FREQ_UNLOCKED;
else
iec958->status[0] &= ~IEC958_AES0_PRO_FREQ_UNLOCKED;
}
changed = 1;
}
if (parms[IDX_SBITS] >= 0) {
if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
iec958->status[2] &= ~IEC958_AES2_PRO_SBITS;
iec958->status[2] |= parms[IDX_SBITS] & 7;
}
changed = 1;
}
if (parms[IDX_WORD] >= 0) {
if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) {
iec958->status[2] &= ~IEC958_AES2_PRO_WORDLEN;
iec958->status[2] |= (parms[IDX_WORD] & 7) << 3;
}
changed = 1;
}
if (parms[IDX_CAT] >= 0) {
if (! (iec958->status[0] & IEC958_AES0_PROFESSIONAL)) {
iec958->status[1] &= ~IEC958_AES1_CON_CATEGORY;
iec958->status[1] |= parms[IDX_CAT] & 0x7f;
}
changed = 1;
}
return changed;
}
int main(int argc, char **argv)
{
const char *dev = "default";
const char *spdif_str = SND_CTL_NAME_IEC958("", PLAYBACK, DEFAULT);
int spdif_index = -1;
snd_ctl_t *ctl;
snd_ctl_elem_list_t *clist;
snd_ctl_elem_id_t *cid;
snd_ctl_elem_value_t *cval;
snd_aes_iec958_t iec958;
int from_stdin = 0;
int dumphex = 0;
int i, c, err;
unsigned int controls, cidx;
char tmpname[32];
int parms[IDX_LAST];
for (i = 0; i < IDX_LAST; i++)
parms[i] = -1; /* not set */
while ((c = getopt(argc, argv, "D:c:n:xhi")) != -1) {
switch (c) {
case 'D':
dev = optarg;
break;
case 'c':
i = atoi(optarg);
if (i < 0 || i >= 32) {
fprintf(stderr, "invalid card index %d\n", i);
return 1;
}
sprintf(tmpname, "hw:%d", i);
dev = tmpname;
break;
case 'n':
spdif_index = atoi(optarg);
break;
case 'x':
dumphex = 1;
break;
case 'i':
from_stdin = 1;
break;
default:
usage();
return 1;
}
}
if ((err = snd_ctl_open(&ctl, dev, 0)) < 0) {
error("snd_ctl_open", err);
return 1;
}
snd_ctl_elem_list_alloca(&clist);
if ((err = snd_ctl_elem_list(ctl, clist)) < 0) {
error("snd_ctl_elem_list", err);
return 1;
}
if ((err = snd_ctl_elem_list_alloc_space(clist, snd_ctl_elem_list_get_count(clist))) < 0) {
error("snd_ctl_elem_list_alloc_space", err);
return 1;
}
if ((err = snd_ctl_elem_list(ctl, clist)) < 0) {
error("snd_ctl_elem_list", err);
return 1;
}
controls = snd_ctl_elem_list_get_used(clist);
for (cidx = 0; cidx < controls; cidx++) {
if (!strcmp(snd_ctl_elem_list_get_name(clist, cidx), spdif_str))
if (spdif_index < 0 ||
snd_ctl_elem_list_get_index(clist, cidx) == spdif_index)
break;
}
if (cidx >= controls) {
fprintf(stderr, "control \"%s\" (index %d) not found\n",
spdif_str, spdif_index);
return 1;
}
snd_ctl_elem_id_alloca(&cid);
snd_ctl_elem_list_get_id(clist, cidx, cid);
snd_ctl_elem_value_alloca(&cval);
snd_ctl_elem_value_set_id(cval, cid);
if ((err = snd_ctl_elem_read(ctl, cval)) < 0) {
error("snd_ctl_elem_read", err);
return 1;
}
snd_ctl_elem_value_get_iec958(cval, &iec958);
/* parse from stdin */
if (from_stdin)
parse_file(parms, stdin);
/* parse commands */
for (c = optind; c < argc - 1; c += 2)
parse_command(parms, argv[c], argv[c + 1]);
if (update_iec958_status(&iec958, parms)) {
/* store the values */
snd_ctl_elem_value_set_iec958(cval, &iec958);
if ((err = snd_ctl_elem_write(ctl, cval)) < 0) {
error("snd_ctl_elem_write", err);
return 1;
}
if ((err = snd_ctl_elem_read(ctl, cval)) < 0) {
error("snd_ctl_elem_write", err);
return 1;
}
snd_ctl_elem_value_get_iec958(cval, &iec958);
}
if (dumphex)
printf("AES0=0x%02x,AES1=0x%02x,AES2=0x%02x,AES3=0x%02x\n",
iec958.status[0], iec958.status[1], iec958.status[2], iec958.status[3]);
else
dump_iec958(&iec958);
snd_ctl_close(ctl);
return 0;
}