4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
35 #include <sys/types.h>
37 #include <sys/mkdev.h>
41 #include <sys/param.h>
42 #include <sys/soundcard.h>
43 #include <libdevinfo.h>
45 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
46 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
49 #define _(s) gettext(s)
53 #define AUDIO_CTRL_STEREO_LEFT(v) ((uint8_t)((v) & 0xff))
54 #define AUDIO_CTRL_STEREO_RIGHT(v) ((uint8_t)(((v) >> 8) & 0xff))
55 #define AUDIO_CTRL_STEREO_VAL(l, r) (((l) & 0xff) | (((r) & 0xff) << 8))
58 * These are borrowed from sys/audio/audio_common.h, where the values
59 * are protected by _KERNEL.
61 #define AUDIO_MN_TYPE_NBITS (4)
62 #define AUDIO_MN_TYPE_MASK ((1U << AUDIO_MN_TYPE_NBITS) - 1)
63 #define AUDIO_MINOR_MIXER (0)
67 * Column display information
68 * All are related to the types enumerated in col_t and any change should be
69 * reflected in the corresponding indices and offsets for all the variables
70 * accordingly. Most tweaks to the display can be done by adjusting the
74 /* types of columns displayed */
75 typedef enum { COL_DV
= 0, COL_NM
, COL_VAL
, COL_SEL
} col_t
;
77 /* corresponding sizes of columns; does not include trailing null */
84 /* corresponding sizes of columns, indexed by col_t value */
85 static int col_sz
[] = {
86 COL_DV_SZ
, COL_NM_SZ
, COL_VAL_SZ
, COL_SEL_SZ
89 /* used by callers of the printing function */
90 typedef struct col_prt
{
97 /* columns displayed in order with vopt = 0 */
98 static int col_dpy
[] = {COL_NM
, COL_VAL
};
99 static int col_dpy_len
= sizeof (col_dpy
) / sizeof (*col_dpy
);
101 /* tells the printing function what members to use; follows col_dpy[] */
102 static size_t col_dpy_prt
[] = {
103 offsetof(col_prt_t
, col_nm
),
104 offsetof(col_prt_t
, col_val
),
107 /* columns displayed in order with vopt = 1 */
108 static int col_dpy_vopt
[] = { COL_DV
, COL_NM
, COL_VAL
, COL_SEL
};
109 static int col_dpy_vopt_len
= sizeof (col_dpy_vopt
) / sizeof (*col_dpy_vopt
);
111 /* tells the printing function what members to use; follows col_dpy_vopt[] */
112 static size_t col_dpy_prt_vopt
[] = {
113 offsetof(col_prt_t
, col_dv
),
114 offsetof(col_prt_t
, col_nm
),
115 offsetof(col_prt_t
, col_val
),
116 offsetof(col_prt_t
, col_sel
)
119 /* columns displayed in order with tofile = 1 */
120 static int col_dpy_tofile
[] = { COL_NM
, COL_VAL
};
121 static int col_dpy_tofile_len
= sizeof (col_dpy_tofile
) /
122 sizeof (*col_dpy_tofile
);
124 /* tells the printing function what members to use; follows col_dpy_tofile[] */
125 static size_t col_dpy_prt_tofile
[] = {
126 offsetof(col_prt_t
, col_nm
),
127 offsetof(col_prt_t
, col_val
)
132 * mixer and control accounting
135 typedef struct cinfo
{
137 oss_mixer_enuminfo
*enump
;
140 typedef struct device
{
150 struct device
*nextp
;
153 static device_t
*devices
= NULL
;
162 (void) vprintf(fmt
, ap
);
173 (void) vfprintf(stderr
, fmt
, ap
);
178 free_device(device_t
*d
)
184 while ((*dpp
) && ((*dpp
) != d
)) {
185 dpp
= &((*dpp
)->nextp
);
190 for (i
= 0; i
< d
->cmax
; i
++) {
191 free(d
->controls
[i
].enump
);
195 (void) close(d
->mfd
);
203 device_t
*d
= devices
;
205 while ((d
= devices
) != NULL
) {
214 * adds to the end of global devices and returns a pointer to the new entry
220 device_t
*d
= calloc(1, sizeof (*d
));
226 if (devices
== NULL
) {
229 for (p
= devices
; p
->nextp
!= NULL
; p
= p
->nextp
) {}
238 * cinfop->enump needs to be present
239 * idx should be: >= 0 to < cinfop->ci.maxvalue
242 get_enum_str(cinfo_t
*cinfop
, int idx
)
244 int sz
= sizeof (*cinfop
->ci
.enum_present
) * 8;
246 if (cinfop
->ci
.enum_present
[idx
/ sz
] & (1 << (idx
% sz
)))
247 return (cinfop
->enump
->strings
+ cinfop
->enump
->strindex
[idx
]);
254 * caller fills in d->mixer.devnode; func fills in the rest
257 get_device_info(device_t
*d
)
263 if ((fd
= open(d
->mixer
.devnode
, O_RDWR
)) < 0) {
264 perror(_("Error opening device"));
270 if (ioctl(fd
, SNDCTL_MIX_NREXT
, &d
->cmax
) < 0) {
271 perror(_("Error getting control count"));
275 d
->controls
= calloc(d
->cmax
, sizeof (*d
->controls
));
277 for (i
= 0; i
< d
->cmax
; i
++) {
278 ci
= &d
->controls
[i
];
283 if (ioctl(fd
, SNDCTL_MIX_EXTINFO
, &ci
->ci
) < 0) {
284 perror(_("Error getting control info"));
288 if (ci
->ci
.type
== MIXT_ENUM
) {
289 ci
->enump
= calloc(1, sizeof (*ci
->enump
));
291 ci
->enump
->ctrl
= ci
->ci
.ctrl
;
293 if (ioctl(fd
, SNDCTL_MIX_ENUMINFO
, ci
->enump
) < 0) {
294 perror(_("Error getting enum info"));
313 if (devices
!= NULL
) {
318 if ((fd
= open("/dev/mixer", O_RDWR
)) < 0) {
320 warn(_("Error opening mixer\n"));
324 if (ioctl(fd
, SNDCTL_SYSINFO
, &si
) < 0) {
326 perror(_("Error getting system information"));
330 for (i
= 0; i
< si
.nummixers
; i
++) {
337 if (ioctl(fd
, SNDCTL_MIXERINFO
, &d
->mixer
) != 0) {
341 d
->card
.card
= d
->mixer
.card_number
;
343 if ((ioctl(fd
, SNDCTL_CARDINFO
, &d
->card
) != 0) ||
344 (stat(d
->mixer
.devnode
, &sbuf
) != 0) ||
345 ((sbuf
.st_mode
& S_IFCHR
) == 0)) {
346 warn(_("Device present: %s\n"), d
->mixer
.devnode
);
350 d
->devt
= makedev(major(sbuf
.st_rdev
),
351 minor(sbuf
.st_rdev
) & ~(AUDIO_MN_TYPE_MASK
));
353 if ((rv
= get_device_info(d
)) != 0) {
369 ctype_valid(int type
)
374 case MIXT_MONOSLIDER
:
375 case MIXT_STEREOSLIDER
:
384 print_control_line(FILE *sfp
, col_prt_t
*colp
, int vopt
)
393 char cbuf
[COL_MAX_SZ
+ 1];
398 col_prtp
= col_dpy_prt_tofile
;
399 col_dpyp
= col_dpy_tofile
;
400 col_cnt
= col_dpy_tofile_len
;
402 col_prtp
= col_dpy_prt_vopt
;
403 col_dpyp
= col_dpy_vopt
;
404 col_cnt
= col_dpy_vopt_len
;
406 col_prtp
= col_dpy_prt
;
408 col_cnt
= col_dpy_len
;
413 for (i
= 0; i
< col_cnt
; i
++) {
414 col_type
= col_dpyp
[i
];
415 width
= col_sz
[col_type
];
416 colstr
= *(char **)(((size_t)colp
) + col_prtp
[i
]);
418 (void) snprintf(cbuf
, sizeof (cbuf
), "%- *s",
419 width
> 0 ? width
: 1,
420 (colstr
== NULL
) ? "" : colstr
);
422 (void) strlcat(line
, cbuf
, sizeof (line
));
424 (void) strlcat(line
, colsep
, sizeof (line
));
427 (void) fprintf(sfp
? sfp
: stdout
, "%s\n", line
);
432 print_header(FILE *sfp
, int vopt
)
437 col
.col_nm
= _("#CONTROL");
438 col
.col_val
= _("VALUE");
440 col
.col_dv
= _("DEVICE");
441 col
.col_nm
= _("CONTROL");
442 col
.col_val
= _("VALUE");
443 col
.col_sel
= _("POSSIBLE");
445 print_control_line(sfp
, &col
, vopt
);
450 print_control(FILE *sfp
, device_t
*d
, cinfo_t
*cinfop
, int vopt
)
453 char *devnm
= d
->card
.shortname
;
454 oss_mixer_value cval
;
459 char valbuf
[COL_VAL_SZ
+ 1];
460 char selbuf
[COL_SEL_SZ
+ 1];
464 cval
.ctrl
= cinfop
->ci
.ctrl
;
466 if (ctype_valid(cinfop
->ci
.type
)) {
467 if (ioctl(mfd
, SNDCTL_MIX_READ
, &cval
) < 0) {
469 perror(_("Error reading control\n"));
477 * convert the control value into a string
479 switch (cinfop
->ci
.type
) {
481 (void) snprintf(valbuf
, sizeof (valbuf
), "%s",
482 cval
.value
? _("on") : _("off"));
485 case MIXT_MONOSLIDER
:
486 (void) snprintf(valbuf
, sizeof (valbuf
), "%d",
490 case MIXT_STEREOSLIDER
:
491 (void) snprintf(valbuf
, sizeof (valbuf
), "%d:%d",
492 (int)AUDIO_CTRL_STEREO_LEFT(cval
.value
),
493 (int)AUDIO_CTRL_STEREO_RIGHT(cval
.value
));
497 str
= get_enum_str(cinfop
, cval
.value
);
499 warn(_("Bad enum index %d for control '%s'\n"),
500 cval
.value
, cinfop
->ci
.extname
);
504 (void) snprintf(valbuf
, sizeof (valbuf
), "%s", str
);
512 * possible control values (range/selection)
514 switch (cinfop
->ci
.type
) {
516 (void) snprintf(selbuf
, sizeof (selbuf
), _("on,off"));
519 case MIXT_MONOSLIDER
:
520 (void) snprintf(selbuf
, sizeof (selbuf
), "%d-%d",
521 cinfop
->ci
.minvalue
, cinfop
->ci
.maxvalue
);
523 case MIXT_STEREOSLIDER
:
524 (void) snprintf(selbuf
, sizeof (selbuf
), "%d-%d:%d-%d",
525 cinfop
->ci
.minvalue
, cinfop
->ci
.maxvalue
,
526 cinfop
->ci
.minvalue
, cinfop
->ci
.maxvalue
);
531 * display the first choice on the same line, then display
532 * the rest on multiple lines
535 for (i
= 0; i
< cinfop
->ci
.maxvalue
; i
++) {
536 str
= get_enum_str(cinfop
, i
);
540 if ((strlen(str
) + 1 + strlen(selbuf
)) >=
544 if (strlen(selbuf
)) {
545 (void) strlcat(selbuf
, ",", sizeof (selbuf
));
548 (void) strlcat(selbuf
, str
, sizeof (selbuf
));
554 (void) snprintf(selbuf
, sizeof (selbuf
), "-");
558 col
.col_nm
= strlen(cinfop
->ci
.extname
) ?
559 cinfop
->ci
.extname
: cinfop
->ci
.id
;
560 while (strchr(col
.col_nm
, '_') != NULL
) {
561 col
.col_nm
= strchr(col
.col_nm
, '_') + 1;
563 col
.col_val
= valbuf
;
564 col
.col_sel
= selbuf
;
565 print_control_line(sfp
, &col
, vopt
);
567 /* non-verbose mode prints don't display the enum values */
568 if ((!vopt
) || (sfp
!= NULL
)) {
572 /* print leftover enum value selections */
573 while ((idx
>= 0) && (idx
< cinfop
->ci
.maxvalue
)) {
575 for (i
= idx
; i
< cinfop
->ci
.maxvalue
; i
++) {
576 str
= get_enum_str(cinfop
, i
);
580 if ((strlen(str
) + 1 + strlen(selbuf
)) >=
584 if (strlen(selbuf
)) {
585 (void) strlcat(selbuf
, ",", sizeof (selbuf
));
588 (void) strlcat(selbuf
, str
, sizeof (selbuf
));
594 col
.col_sel
= selbuf
;
595 print_control_line(sfp
, &col
, vopt
);
603 set_device_control(device_t
*d
, cinfo_t
*cinfop
, char *wstr
, int vopt
)
606 oss_mixer_value cval
;
607 int wlen
= strlen(wstr
);
615 cval
.ctrl
= cinfop
->ci
.ctrl
;
618 switch (cinfop
->ci
.type
) {
620 cval
.value
= (strncmp(_("on"), wstr
, wlen
) == 0) ? 1 : 0;
623 case MIXT_MONOSLIDER
:
624 cval
.value
= atoi(wstr
);
627 case MIXT_STEREOSLIDER
:
629 rstr
= strchr(wstr
, ':');
644 cval
.value
= AUDIO_CTRL_STEREO_VAL(lval
, rval
);
648 for (i
= 0; i
< cinfop
->ci
.maxvalue
; i
++) {
649 str
= get_enum_str(cinfop
, i
);
653 if (strncmp(wstr
, str
, wlen
) == 0) {
659 if (i
>= cinfop
->ci
.maxvalue
) {
660 warn(_("Invalid enumeration value\n"));
666 warn(_("Unsupported control type: %d\n"), cinfop
->ci
.type
);
671 msg(_("%s: '%s' set to '%s'\n"), d
->card
.shortname
,
672 cinfop
->ci
.extname
, wstr
);
675 if (ioctl(mfd
, SNDCTL_MIX_WRITE
, &cval
) < 0) {
677 perror(_("Error writing control"));
689 #define HELP_STR _( \
690 "audioctl list-devices\n" \
691 " list all audio devices\n" \
693 "audioctl show-device [ -v ] [ -d <device> ]\n" \
694 " display information about an audio device\n" \
696 "audioctl show-control [ -v ] [ -d <device> ] [ <control> ... ]\n" \
697 " get the value of a specific control (all if not specified)\n" \
699 "audioctl set-control [ -v ] [ -d <device> ] <control> <value>\n" \
700 " set the value of a specific control\n" \
702 "audioctl save-controls [ -d <device> ] [ -f ] <file>\n" \
703 " save all control settings for the device to a file\n" \
705 "audioctl load-controls [ -d <device> ] <file>\n" \
706 " restore previously saved control settings to device\n" \
709 " show this message.\n")
711 (void) fprintf(stderr
, HELP_STR
);
715 device_devt(char *name
)
719 if ((stat(name
, &sbuf
) != 0) ||
720 ((sbuf
.st_mode
& S_IFCHR
) == 0)) {
721 /* Not a device node! */
725 return (makedev(major(sbuf
.st_rdev
),
726 minor(sbuf
.st_rdev
) & ~(AUDIO_MN_TYPE_MASK
)));
730 find_device(char *name
)
736 * User may have specified:
741 * /dev/audioctl[<num>]
742 * /dev/sound/<num>{,ctl,dsp,mixer}
743 * /dev/sound/<driver>:<num>{,ctl,dsp,mixer}
745 * We can canonicalize these by looking at the dev_t though.
748 if (load_devices() != 0) {
753 name
= getenv("AUDIODEV");
755 if ((name
== NULL
) ||
756 (strcmp(name
, "/dev/mixer") == 0)) {
757 /* /dev/mixer node doesn't point to real hw */
762 /* if we have a full path, convert to the devt */
763 if ((devt
= device_devt(name
)) == 0) {
764 warn(_("No such audio device.\n"));
770 for (d
= devices
; d
!= NULL
; d
= d
->nextp
) {
771 oss_card_info
*card
= &d
->card
;
773 if ((name
) && (strcmp(name
, card
->shortname
) == 0)) {
776 if (devt
== d
->devt
) {
781 warn(_("No such audio device.\n"));
786 do_list_devices(int argc
, char **argv
)
792 while ((optc
= getopt(argc
, argv
, "v")) != EOF
) {
809 if (load_devices() != 0) {
813 for (d
= devices
; d
!= NULL
; d
= d
->nextp
) {
815 if ((d
->mixer
.enabled
== 0) && (!verbose
))
819 msg(_("%s (%s)\n"), d
->card
.shortname
,
822 msg(_("%s\n"), d
->card
.shortname
);
830 do_show_device(int argc
, char **argv
)
833 char *devname
= NULL
;
836 while ((optc
= getopt(argc
, argv
, "d:v")) != EOF
) {
855 if ((d
= find_device(devname
)) == NULL
) {
859 msg(_("Device: %s\n"), d
->mixer
.devnode
);
860 msg(_(" Name = %s\n"), d
->card
.shortname
);
861 msg(_(" Config = %s\n"), d
->card
.longname
);
863 if (strlen(d
->card
.hw_info
)) {
864 msg(_(" HW Info = %s"), d
->card
.hw_info
);
871 do_show_control(int argc
, char **argv
)
877 char *devname
= NULL
;
884 while ((optc
= getopt(argc
, argv
, "d:v")) != EOF
) {
900 if ((d
= find_device(devname
)) == NULL
) {
904 print_header(NULL
, verbose
);
907 for (i
= 0; i
< d
->cmax
; i
++) {
909 cinfop
= &d
->controls
[i
];
910 rv
= print_control(NULL
, d
, cinfop
, verbose
);
911 rval
= rval
? rval
: rv
;
916 for (i
= 0; i
< argc
; i
++) {
917 for (j
= 0; j
< d
->cmax
; j
++) {
918 cinfop
= &d
->controls
[j
];
919 n
= strrchr(cinfop
->ci
.extname
, '_');
920 n
= n
? n
+ 1 : cinfop
->ci
.extname
;
921 if (strcmp(argv
[i
], n
) == 0) {
922 rv
= print_control(NULL
, d
, cinfop
, verbose
);
923 rval
= rval
? rval
: rv
;
927 /* Didn't find requested control */
929 warn(_("No such control: %s\n"), argv
[i
]);
930 rval
= rval
? rval
: ENODEV
;
938 do_set_control(int argc
, char **argv
)
944 char *devname
= NULL
;
953 while ((optc
= getopt(argc
, argv
, "d:v")) != EOF
) {
976 if ((d
= find_device(devname
)) == NULL
) {
980 for (i
= 0, found
= 0; i
< d
->cmax
; i
++) {
981 cinfop
= &d
->controls
[i
];
982 n
= strrchr(cinfop
->ci
.extname
, '_');
983 n
= n
? n
+ 1 : cinfop
->ci
.extname
;
984 if (strcmp(cname
, n
) != 0) {
988 rv
= set_device_control(d
, cinfop
, value
, verbose
);
989 rval
= rval
? rval
: rv
;
992 warn(_("No such control: %s\n"), cname
);
999 do_save_controls(int argc
, char **argv
)
1004 char *devname
= NULL
;
1013 mode
= O_WRONLY
| O_CREAT
| O_EXCL
;
1015 while ((optc
= getopt(argc
, argv
, "d:f")) != EOF
) {
1038 if ((d
= find_device(devname
)) == NULL
) {
1042 if ((fd
= open(fname
, mode
, 0666)) < 0) {
1043 perror(_("Failed to create file"));
1047 if ((fp
= fdopen(fd
, "w")) == NULL
) {
1048 perror(_("Unable to open file\n"));
1050 (void) unlink(fname
);
1054 (void) fprintf(fp
, "# Device: %s\n", d
->mixer
.devnode
);
1055 (void) fprintf(fp
, "# Name = %s\n", d
->card
.shortname
);
1056 (void) fprintf(fp
, "# Config = %s\n", d
->card
.longname
);
1058 if (strlen(d
->card
.hw_info
)) {
1059 (void) fprintf(fp
, "# HW Info = %s", d
->card
.hw_info
);
1061 (void) fprintf(fp
, "#\n");
1063 print_header(fp
, 0);
1065 for (i
= 0; i
< d
->cmax
; i
++) {
1066 cinfop
= &d
->controls
[i
];
1067 rv
= print_control(fp
, d
, cinfop
, 0);
1068 rval
= rval
? rval
: rv
;
1077 do_load_controls(int argc
, char **argv
)
1082 char *devname
= NULL
;
1090 char linebuf
[MAXLINE
];
1094 while ((optc
= getopt(argc
, argv
, "d:")) != EOF
) {
1113 if ((d
= find_device(devname
)) == NULL
) {
1117 if ((fp
= fopen(fname
, "r")) == NULL
) {
1118 perror(_("Unable to open file"));
1122 while (fgets(linebuf
, sizeof (linebuf
), fp
) != NULL
) {
1124 if (linebuf
[strlen(linebuf
) - 1] != '\n') {
1125 warn(_("Warning: line too long at line %d\n"), lineno
);
1126 /* read in the rest of the line and discard it */
1127 while (fgets(linebuf
, sizeof (linebuf
), fp
) != NULL
&&
1128 (linebuf
[strlen(linebuf
) - 1] != '\n')) {
1134 /* we have a good line ... */
1135 cname
= strtok(linebuf
, " \t\n");
1136 /* skip comments and blank lines */
1137 if ((cname
== NULL
) || (cname
[0] == '#')) {
1140 value
= strtok(NULL
, " \t\n");
1141 if ((value
== NULL
) || (*cname
== 0)) {
1142 warn(_("Warning: missing value at line %d\n"), lineno
);
1146 for (i
= 0, found
= 0; i
< d
->cmax
; i
++) {
1147 /* save and restore requires an exact match */
1148 cinfop
= &d
->controls
[i
];
1149 if (strcmp(cinfop
->ci
.extname
, cname
) != 0) {
1153 rv
= set_device_control(d
, cinfop
, value
, 0);
1154 rval
= rval
? rval
: rv
;
1157 warn(_("No such control: %s\n"), cname
);
1166 mixer_walker(di_devlink_t dlink
, void *arg
)
1171 int verbose
= *(int *)arg
;
1174 num_offset
= sizeof ("/dev/mixer") - 1;
1176 link
= di_devlink_path(dlink
);
1178 if ((link
== NULL
) ||
1179 (strncmp(link
, "/dev/mixer", num_offset
) != 0) ||
1180 (!isdigit(link
[num_offset
]))) {
1181 return (DI_WALK_CONTINUE
);
1184 num
= atoi(link
+ num_offset
);
1185 if ((fd
= open(link
, O_RDWR
)) < 0) {
1187 if (errno
== ENOENT
) {
1188 msg(_("Device %s not present.\n"), link
);
1190 msg(_("Unable to open device %s: %s\n"),
1191 link
, strerror(errno
));
1194 return (DI_WALK_CONTINUE
);
1198 msg(_("Initializing link %s: "), link
);
1200 if (ioctl(fd
, SNDCTL_SUN_SEND_NUMBER
, &num
) != 0) {
1202 msg(_("failed: %s\n"), strerror(errno
));
1210 return (DI_WALK_CONTINUE
);
1214 do_init_devices(int argc
, char **argv
)
1217 di_devlink_handle_t dlh
;
1220 while ((optc
= getopt(argc
, argv
, "v")) != EOF
) {
1238 dlh
= di_devlink_init(NULL
, 0);
1240 perror(_("Unable to initialize devlink handle"));
1244 if (di_devlink_walk(dlh
, "^mixer", NULL
, 0, &verbose
,
1245 mixer_walker
) != 0) {
1246 perror(_("Unable to walk devlinks"));
1253 main(int argc
, char **argv
)
1258 (void) setlocale(LC_ALL
, "");
1259 (void) textdomain(TEXT_DOMAIN
);
1261 while ((opt
= getopt(argc
, argv
, "h")) != EOF
) {
1283 } else if (strcmp(argv
[0], "help") == 0) {
1286 } else if (strcmp(argv
[0], "list-devices") == 0) {
1287 rv
= do_list_devices(argc
, argv
);
1288 } else if (strcmp(argv
[0], "show-device") == 0) {
1289 rv
= do_show_device(argc
, argv
);
1290 } else if (strcmp(argv
[0], "show-control") == 0) {
1291 rv
= do_show_control(argc
, argv
);
1292 } else if (strcmp(argv
[0], "set-control") == 0) {
1293 rv
= do_set_control(argc
, argv
);
1294 } else if (strcmp(argv
[0], "load-controls") == 0) {
1295 rv
= do_load_controls(argc
, argv
);
1296 } else if (strcmp(argv
[0], "save-controls") == 0) {
1297 rv
= do_save_controls(argc
, argv
);
1298 } else if (strcmp(argv
[0], "init-devices") == 0) {
1299 rv
= do_init_devices(argc
, argv
);