iecset.c (10997B)
1 /* 2 iecset - change IEC958 status bits on ALSA 3 Copyright (C) 2003 by Takashi Iwai <tiwai@suse.de> 4 5 This program is free software; you can redistribute it and/or 6 modify it under the terms of the GNU General Public License 7 as published by the Free Software Foundation; either version 2 8 of the License, or (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 */ 19 20 #include <stdio.h> 21 #include <ctype.h> 22 #include <alsa/asoundlib.h> 23 24 void dump_iec958(snd_aes_iec958_t *iec); 25 26 static int get_bool(const char *str) 27 { 28 if (strncmp(str, "yes", 3) == 0 || 29 strncmp(str, "YES", 3) == 0 || 30 strncmp(str, "on", 2) == 0 || 31 strncmp(str, "ON", 2) == 0 || 32 strncmp(str, "true", 4) == 0 || 33 strncmp(str, "TRUE", 4) == 0 || 34 *str == '1') 35 return 1; 36 return 0; 37 } 38 39 enum { 40 CMD_BOOL, CMD_BOOL_INV, CMD_INT 41 }; 42 43 enum { 44 IDX_PRO, IDX_NOAUDIO, IDX_RATE, IDX_UNLOCK, IDX_SBITS, IDX_WORD, IDX_EMP, IDX_CAT, IDX_NOCOPY, IDX_ORIG, 45 IDX_LAST 46 }; 47 48 struct cmdtbl { 49 const char *name; 50 int idx; 51 int type; 52 const char *desc; 53 }; 54 55 static const struct cmdtbl cmds[] = { 56 { "pro", IDX_PRO, CMD_BOOL, 57 "professional (common)\n\toff = consumer mode, on = professional mode" }, 58 { "aud", IDX_NOAUDIO, CMD_BOOL_INV, 59 "audio (common)\n\ton = audio mode, off = non-audio mode" }, 60 { "rat", IDX_RATE, CMD_INT, 61 "rate (common)\n\tsample rate in Hz (0 = not indicated)" }, 62 { "emp", IDX_EMP, CMD_INT, 63 "emphasis (common)\n\t0 = none, 1 = 50/15us, 2 = CCITT" }, 64 { "loc", IDX_UNLOCK, CMD_BOOL_INV, 65 "lock (prof.)\n\toff = rate unlocked, on = rate locked" }, 66 { "sbi", IDX_SBITS, CMD_INT, 67 "sbits (prof.)\n\tsample bits 2 = 20bit, 4 = 24bit, 6 = undef" }, 68 { "wor", IDX_WORD, CMD_INT, 69 "wordlength (prof.)\n\t0=no, 2=22-18bit, 4=23-19bit, 5=24-20bit, 6=20-16bit" }, 70 { "cat", IDX_CAT, CMD_INT, 71 "category (consumer)\n\t0-0x7f" }, 72 { "cop", IDX_NOCOPY, CMD_BOOL_INV, 73 "copyright (consumer)\n\toff = non-copyright, on = copyright" }, 74 { "ori", IDX_ORIG, CMD_BOOL, 75 "original (consumer)\n\toff = 1st-gen, on = original" }, 76 }; 77 78 79 static void error(const char *s, int err) 80 { 81 fprintf(stderr, "%s: %s\n", s, snd_strerror(err)); 82 } 83 84 85 static void usage(void) 86 { 87 int i; 88 89 printf("Usage: iecset [options] [cmd arg...]\n"); 90 printf("Options:\n"); 91 printf(" -D device specifies the control device to use\n"); 92 printf(" -c card specifies the card number to use (equiv. with -Dhw:#)\n"); 93 printf(" -n number specifies the control index number (default = 0)\n"); 94 printf(" -x dump the dump the AESx hex code for IEC958 PCM parameters\n"); 95 printf(" -i read commands from stdin\n"); 96 printf("Commands:\n"); 97 for (i = 0; i < (int)(sizeof(cmds)/sizeof(cmds[0])); i++) { 98 printf(" %s\n", cmds[i].desc); 99 } 100 } 101 102 103 /* 104 * parse iecset commands 105 */ 106 static void parse_command(int *parms, const char *c, const char *arg) 107 { 108 int i; 109 110 for (i = 0; i < (int)(sizeof(cmds)/sizeof(cmds[0])); i++) { 111 if (strncmp(c, cmds[i].name, strlen(cmds[i].name)) == 0) { 112 int val; 113 switch (cmds[i].type) { 114 case CMD_BOOL: 115 val = get_bool(arg); 116 break; 117 case CMD_BOOL_INV: 118 val = !get_bool(arg); 119 break; 120 case CMD_INT: 121 default: 122 val = (int)strtol(arg, NULL, 0); 123 break; 124 } 125 parms[cmds[i].idx] = val; 126 return; 127 } 128 } 129 } 130 131 static char *skipspace(char *line) 132 { 133 char *p; 134 for (p = line; *p && isspace(*p); p++) 135 ; 136 return p; 137 } 138 139 /* 140 * parse iecset commands from the file 141 */ 142 static void parse_file(int *parms, FILE *fp) 143 { 144 char line[1024], *cmd, *arg; 145 while (fgets(line, sizeof(line), fp) != NULL) { 146 cmd = skipspace(line); 147 if (*cmd == '#' || ! *cmd) 148 continue; 149 for (arg = cmd; *arg && !isspace(*arg); arg++) 150 ; 151 if (! *arg) 152 continue; 153 *arg++ = 0; 154 arg = skipspace(arg); 155 if (! *arg) 156 continue; 157 parse_command(parms, cmd, arg); 158 } 159 } 160 161 /* update iec958 status values 162 * return non-zero if the values are modified 163 */ 164 static int update_iec958_status(snd_aes_iec958_t *iec958, int *parms) 165 { 166 int changed = 0; 167 if (parms[IDX_PRO] >= 0) { 168 if (parms[IDX_PRO]) 169 iec958->status[0] |= IEC958_AES0_PROFESSIONAL; 170 else 171 iec958->status[0] &= ~IEC958_AES0_PROFESSIONAL; 172 changed = 1; 173 } 174 if (parms[IDX_NOAUDIO] >= 0) { 175 if (parms[IDX_NOAUDIO]) 176 iec958->status[0] |= IEC958_AES0_NONAUDIO; 177 else 178 iec958->status[0] &= ~IEC958_AES0_NONAUDIO; 179 changed = 1; 180 } 181 if (parms[IDX_RATE] >= 0) { 182 if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) { 183 iec958->status[0] &= ~IEC958_AES0_PRO_FS; 184 switch (parms[IDX_RATE]) { 185 case 44100: 186 iec958->status[0] |= IEC958_AES0_PRO_FS_44100; 187 break; 188 case 48000: 189 iec958->status[0] |= IEC958_AES0_PRO_FS_48000; 190 break; 191 case 32000: 192 iec958->status[0] |= IEC958_AES0_PRO_FS_32000; 193 break; 194 } 195 } else { 196 iec958->status[3] &= ~IEC958_AES3_CON_FS; 197 switch (parms[IDX_RATE]) { 198 case 22050: 199 iec958->status[3] |= IEC958_AES3_CON_FS_22050; 200 break; 201 case 24000: 202 iec958->status[3] |= IEC958_AES3_CON_FS_24000; 203 break; 204 case 32000: 205 iec958->status[3] |= IEC958_AES3_CON_FS_32000; 206 break; 207 case 44100: 208 iec958->status[3] |= IEC958_AES3_CON_FS_44100; 209 break; 210 case 48000: 211 iec958->status[3] |= IEC958_AES3_CON_FS_48000; 212 break; 213 case 88200: 214 iec958->status[3] |= IEC958_AES3_CON_FS_88200;; 215 break; 216 case 96000: 217 iec958->status[3] |= IEC958_AES3_CON_FS_96000; 218 break; 219 case 176400: 220 iec958->status[3] |= IEC958_AES3_CON_FS_176400; 221 break; 222 case 192000: 223 iec958->status[3] |= IEC958_AES3_CON_FS_192000; 224 break; 225 case 768000: 226 iec958->status[3] |= IEC958_AES3_CON_FS_768000; 227 break; 228 default: 229 iec958->status[3] |= IEC958_AES3_CON_FS_NOTID; 230 break; 231 } 232 } 233 changed = 1; 234 } 235 if (parms[IDX_NOCOPY] >= 0) { 236 if (! (iec958->status[0] & IEC958_AES0_PROFESSIONAL)) { 237 if (parms[IDX_NOCOPY]) 238 iec958->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT; 239 else 240 iec958->status[0] &= ~IEC958_AES0_CON_NOT_COPYRIGHT; 241 } 242 changed = 1; 243 } 244 if (parms[IDX_ORIG] >= 0) { 245 if (! (iec958->status[0] & IEC958_AES0_PROFESSIONAL)) { 246 if (parms[IDX_ORIG]) 247 iec958->status[1] |= IEC958_AES1_CON_ORIGINAL; 248 else 249 iec958->status[1] &= ~IEC958_AES1_CON_ORIGINAL; 250 } 251 changed = 1; 252 } 253 if (parms[IDX_EMP] >= 0) { 254 if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) { 255 iec958->status[0] &= ~IEC958_AES0_PRO_EMPHASIS; 256 switch (parms[IDX_EMP]) { 257 case 0: 258 iec958->status[0] |= IEC958_AES0_PRO_EMPHASIS_NONE; 259 break; 260 case 1: 261 iec958->status[0] |= IEC958_AES0_PRO_EMPHASIS_5015; 262 break; 263 case 2: 264 iec958->status[0] |= IEC958_AES0_PRO_EMPHASIS_CCITT; 265 break; 266 } 267 } else { 268 if (parms[IDX_EMP]) 269 iec958->status[0] |= IEC958_AES0_CON_EMPHASIS_5015; 270 else 271 iec958->status[0] &= ~IEC958_AES0_CON_EMPHASIS_5015; 272 } 273 changed = 1; 274 } 275 if (parms[IDX_UNLOCK] >= 0) { 276 if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) { 277 if (parms[IDX_UNLOCK]) 278 iec958->status[0] |= IEC958_AES0_PRO_FREQ_UNLOCKED; 279 else 280 iec958->status[0] &= ~IEC958_AES0_PRO_FREQ_UNLOCKED; 281 } 282 changed = 1; 283 } 284 if (parms[IDX_SBITS] >= 0) { 285 if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) { 286 iec958->status[2] &= ~IEC958_AES2_PRO_SBITS; 287 iec958->status[2] |= parms[IDX_SBITS] & 7; 288 } 289 changed = 1; 290 } 291 if (parms[IDX_WORD] >= 0) { 292 if (iec958->status[0] & IEC958_AES0_PROFESSIONAL) { 293 iec958->status[2] &= ~IEC958_AES2_PRO_WORDLEN; 294 iec958->status[2] |= (parms[IDX_WORD] & 7) << 3; 295 } 296 changed = 1; 297 } 298 if (parms[IDX_CAT] >= 0) { 299 if (! (iec958->status[0] & IEC958_AES0_PROFESSIONAL)) { 300 iec958->status[1] &= ~IEC958_AES1_CON_CATEGORY; 301 iec958->status[1] |= parms[IDX_CAT] & 0x7f; 302 } 303 changed = 1; 304 } 305 306 return changed; 307 } 308 309 310 int main(int argc, char **argv) 311 { 312 const char *dev = "default"; 313 const char *spdif_str = SND_CTL_NAME_IEC958("", PLAYBACK, DEFAULT); 314 int spdif_index = -1; 315 snd_ctl_t *ctl; 316 snd_ctl_elem_list_t *clist; 317 snd_ctl_elem_id_t *cid; 318 snd_ctl_elem_value_t *cval; 319 snd_aes_iec958_t iec958; 320 int from_stdin = 0; 321 int dumphex = 0; 322 int i, c, err; 323 unsigned int controls, cidx; 324 char tmpname[32]; 325 int parms[IDX_LAST]; 326 327 for (i = 0; i < IDX_LAST; i++) 328 parms[i] = -1; /* not set */ 329 330 while ((c = getopt(argc, argv, "D:c:n:xhi")) != -1) { 331 switch (c) { 332 case 'D': 333 dev = optarg; 334 break; 335 case 'c': 336 i = atoi(optarg); 337 if (i < 0 || i >= 32) { 338 fprintf(stderr, "invalid card index %d\n", i); 339 return 1; 340 } 341 sprintf(tmpname, "hw:%d", i); 342 dev = tmpname; 343 break; 344 case 'n': 345 spdif_index = atoi(optarg); 346 break; 347 case 'x': 348 dumphex = 1; 349 break; 350 case 'i': 351 from_stdin = 1; 352 break; 353 default: 354 usage(); 355 return 1; 356 } 357 } 358 359 if ((err = snd_ctl_open(&ctl, dev, 0)) < 0) { 360 error("snd_ctl_open", err); 361 return 1; 362 } 363 364 snd_ctl_elem_list_alloca(&clist); 365 if ((err = snd_ctl_elem_list(ctl, clist)) < 0) { 366 error("snd_ctl_elem_list", err); 367 return 1; 368 } 369 if ((err = snd_ctl_elem_list_alloc_space(clist, snd_ctl_elem_list_get_count(clist))) < 0) { 370 error("snd_ctl_elem_list_alloc_space", err); 371 return 1; 372 } 373 if ((err = snd_ctl_elem_list(ctl, clist)) < 0) { 374 error("snd_ctl_elem_list", err); 375 return 1; 376 } 377 378 controls = snd_ctl_elem_list_get_used(clist); 379 for (cidx = 0; cidx < controls; cidx++) { 380 if (!strcmp(snd_ctl_elem_list_get_name(clist, cidx), spdif_str)) 381 if (spdif_index < 0 || 382 snd_ctl_elem_list_get_index(clist, cidx) == spdif_index) 383 break; 384 } 385 if (cidx >= controls) { 386 fprintf(stderr, "control \"%s\" (index %d) not found\n", 387 spdif_str, spdif_index); 388 return 1; 389 } 390 391 snd_ctl_elem_id_alloca(&cid); 392 snd_ctl_elem_list_get_id(clist, cidx, cid); 393 snd_ctl_elem_value_alloca(&cval); 394 snd_ctl_elem_value_set_id(cval, cid); 395 if ((err = snd_ctl_elem_read(ctl, cval)) < 0) { 396 error("snd_ctl_elem_read", err); 397 return 1; 398 } 399 400 snd_ctl_elem_value_get_iec958(cval, &iec958); 401 402 /* parse from stdin */ 403 if (from_stdin) 404 parse_file(parms, stdin); 405 406 /* parse commands */ 407 for (c = optind; c < argc - 1; c += 2) 408 parse_command(parms, argv[c], argv[c + 1]); 409 410 if (update_iec958_status(&iec958, parms)) { 411 /* store the values */ 412 snd_ctl_elem_value_set_iec958(cval, &iec958); 413 if ((err = snd_ctl_elem_write(ctl, cval)) < 0) { 414 error("snd_ctl_elem_write", err); 415 return 1; 416 } 417 if ((err = snd_ctl_elem_read(ctl, cval)) < 0) { 418 error("snd_ctl_elem_write", err); 419 return 1; 420 } 421 snd_ctl_elem_value_get_iec958(cval, &iec958); 422 } 423 424 if (dumphex) 425 printf("AES0=0x%02x,AES1=0x%02x,AES2=0x%02x,AES3=0x%02x\n", 426 iec958.status[0], iec958.status[1], iec958.status[2], iec958.status[3]); 427 else 428 dump_iec958(&iec958); 429 430 snd_ctl_close(ctl); 431 return 0; 432 }