Blame iecset/iecset.c

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