xref: /onnv-gate/usr/src/cmd/audio/audioctl/audioctl.c (revision 11423:4570ae6cb45b)
111230Sgdamore@opensolaris.org /*
211230Sgdamore@opensolaris.org  * CDDL HEADER START
311230Sgdamore@opensolaris.org  *
411230Sgdamore@opensolaris.org  * The contents of this file are subject to the terms of the
511230Sgdamore@opensolaris.org  * Common Development and Distribution License (the "License").
611230Sgdamore@opensolaris.org  * You may not use this file except in compliance with the License.
711230Sgdamore@opensolaris.org  *
811230Sgdamore@opensolaris.org  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911230Sgdamore@opensolaris.org  * or http://www.opensolaris.org/os/licensing.
1011230Sgdamore@opensolaris.org  * See the License for the specific language governing permissions
1111230Sgdamore@opensolaris.org  * and limitations under the License.
1211230Sgdamore@opensolaris.org  *
1311230Sgdamore@opensolaris.org  * When distributing Covered Code, include this CDDL HEADER in each
1411230Sgdamore@opensolaris.org  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511230Sgdamore@opensolaris.org  * If applicable, add the following below this CDDL HEADER, with the
1611230Sgdamore@opensolaris.org  * fields enclosed by brackets "[]" replaced with your own identifying
1711230Sgdamore@opensolaris.org  * information: Portions Copyright [yyyy] [name of copyright owner]
1811230Sgdamore@opensolaris.org  *
1911230Sgdamore@opensolaris.org  * CDDL HEADER END
2011230Sgdamore@opensolaris.org  */
2111230Sgdamore@opensolaris.org /*
22*11423Sgdamore@opensolaris.org  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2311230Sgdamore@opensolaris.org  * Use is subject to license terms.
2411230Sgdamore@opensolaris.org  */
2511230Sgdamore@opensolaris.org 
2611230Sgdamore@opensolaris.org #include <stdio.h>
2711230Sgdamore@opensolaris.org #include <stdlib.h>
2811230Sgdamore@opensolaris.org #include <errno.h>
2911230Sgdamore@opensolaris.org #include <string.h>
3011230Sgdamore@opensolaris.org #include <strings.h>
3111230Sgdamore@opensolaris.org #include <locale.h>
3211230Sgdamore@opensolaris.org #include <libintl.h>
3311230Sgdamore@opensolaris.org #include <stdarg.h>
3411230Sgdamore@opensolaris.org #include <stddef.h>
3511230Sgdamore@opensolaris.org #include <sys/types.h>
3611230Sgdamore@opensolaris.org #include <sys/stat.h>
3711230Sgdamore@opensolaris.org #include <sys/mkdev.h>
3811230Sgdamore@opensolaris.org #include <fcntl.h>
3911230Sgdamore@opensolaris.org #include <unistd.h>
4011230Sgdamore@opensolaris.org #include <ctype.h>
4111230Sgdamore@opensolaris.org #include <sys/param.h>
4211230Sgdamore@opensolaris.org #include <sys/soundcard.h>
4311253Sgdamore@opensolaris.org #include <libdevinfo.h>
4411230Sgdamore@opensolaris.org 
4511230Sgdamore@opensolaris.org #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
4611230Sgdamore@opensolaris.org #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
4711230Sgdamore@opensolaris.org #endif
4811230Sgdamore@opensolaris.org 
4911230Sgdamore@opensolaris.org #define	_(s)	gettext(s)
5011230Sgdamore@opensolaris.org 
5111230Sgdamore@opensolaris.org #define	MAXLINE	1024
5211230Sgdamore@opensolaris.org 
5311230Sgdamore@opensolaris.org #define	AUDIO_CTRL_STEREO_LEFT(v)	((uint8_t)((v) & 0xff))
5411230Sgdamore@opensolaris.org #define	AUDIO_CTRL_STEREO_RIGHT(v)	((uint8_t)(((v) >> 8) & 0xff))
5511230Sgdamore@opensolaris.org #define	AUDIO_CTRL_STEREO_VAL(l, r)	(((l) & 0xff) | (((r) & 0xff) << 8))
5611230Sgdamore@opensolaris.org 
5711230Sgdamore@opensolaris.org /*
5811230Sgdamore@opensolaris.org  * These are borrowed from sys/audio/audio_common.h, where the values
5911230Sgdamore@opensolaris.org  * are protected by _KERNEL.
6011230Sgdamore@opensolaris.org  */
6111230Sgdamore@opensolaris.org #define	AUDIO_MN_TYPE_NBITS	(4)
6211230Sgdamore@opensolaris.org #define	AUDIO_MN_TYPE_MASK	((1U << AUDIO_MN_TYPE_NBITS) - 1)
6311230Sgdamore@opensolaris.org #define	AUDIO_MINOR_MIXER	(0)
6411230Sgdamore@opensolaris.org 
6511230Sgdamore@opensolaris.org 
6611230Sgdamore@opensolaris.org /*
6711230Sgdamore@opensolaris.org  * Column display information
6811230Sgdamore@opensolaris.org  * All are related to the types enumerated in col_t and any change should be
6911230Sgdamore@opensolaris.org  * reflected in the corresponding indices and offsets for all the variables
7011230Sgdamore@opensolaris.org  * accordingly.  Most tweaks to the display can be done by adjusting the
7111230Sgdamore@opensolaris.org  * values here.
7211230Sgdamore@opensolaris.org  */
7311230Sgdamore@opensolaris.org 
7411230Sgdamore@opensolaris.org /* types of columns displayed */
7511230Sgdamore@opensolaris.org typedef enum { COL_DV = 0, COL_NM, COL_VAL, COL_SEL} col_t;
7611230Sgdamore@opensolaris.org 
7711230Sgdamore@opensolaris.org /* corresponding sizes of columns; does not include trailing null */
7811230Sgdamore@opensolaris.org #define	COL_DV_SZ	16
7911230Sgdamore@opensolaris.org #define	COL_NM_SZ	24
8011230Sgdamore@opensolaris.org #define	COL_VAL_SZ	10
8111230Sgdamore@opensolaris.org #define	COL_SEL_SZ	20
8211230Sgdamore@opensolaris.org #define	COL_MAX_SZ	64
8311230Sgdamore@opensolaris.org 
8411230Sgdamore@opensolaris.org /* corresponding sizes of columns, indexed by col_t value */
8511230Sgdamore@opensolaris.org static int col_sz[] = {
8611230Sgdamore@opensolaris.org 	COL_DV_SZ, COL_NM_SZ, COL_VAL_SZ, COL_SEL_SZ
8711230Sgdamore@opensolaris.org };
8811230Sgdamore@opensolaris.org 
8911230Sgdamore@opensolaris.org /* used by callers of the printing function */
9011230Sgdamore@opensolaris.org typedef struct col_prt {
9111230Sgdamore@opensolaris.org 	char *col_dv;
9211230Sgdamore@opensolaris.org 	char *col_nm;
9311230Sgdamore@opensolaris.org 	char *col_val;
9411230Sgdamore@opensolaris.org 	char *col_sel;
9511230Sgdamore@opensolaris.org } col_prt_t;
9611230Sgdamore@opensolaris.org 
9711230Sgdamore@opensolaris.org /* columns displayed in order with vopt = 0 */
9811230Sgdamore@opensolaris.org static int col_dpy[] = {COL_NM, COL_VAL};
9911230Sgdamore@opensolaris.org static int col_dpy_len = sizeof (col_dpy) / sizeof (*col_dpy);
10011230Sgdamore@opensolaris.org 
10111230Sgdamore@opensolaris.org /* tells the printing function what members to use; follows col_dpy[] */
10211230Sgdamore@opensolaris.org static size_t col_dpy_prt[] = {
10311230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_nm),
10411230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_val),
10511230Sgdamore@opensolaris.org };
10611230Sgdamore@opensolaris.org 
10711230Sgdamore@opensolaris.org /* columns displayed in order with vopt = 1 */
10811230Sgdamore@opensolaris.org static int col_dpy_vopt[] = { COL_DV, COL_NM, COL_VAL, COL_SEL};
10911230Sgdamore@opensolaris.org static int col_dpy_vopt_len = sizeof (col_dpy_vopt) / sizeof (*col_dpy_vopt);
11011230Sgdamore@opensolaris.org 
11111230Sgdamore@opensolaris.org /* tells the printing function what members to use; follows col_dpy_vopt[] */
11211230Sgdamore@opensolaris.org static size_t col_dpy_prt_vopt[] = {
11311230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_dv),
11411230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_nm),
11511230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_val),
11611230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_sel)
11711230Sgdamore@opensolaris.org };
11811230Sgdamore@opensolaris.org 
11911230Sgdamore@opensolaris.org /* columns displayed in order with tofile = 1 */
12011230Sgdamore@opensolaris.org static int col_dpy_tofile[] = { COL_NM, COL_VAL};
12111230Sgdamore@opensolaris.org static int col_dpy_tofile_len = sizeof (col_dpy_tofile) /
12211230Sgdamore@opensolaris.org     sizeof (*col_dpy_tofile);
12311230Sgdamore@opensolaris.org 
12411230Sgdamore@opensolaris.org /* tells the printing function what members to use; follows col_dpy_tofile[] */
12511230Sgdamore@opensolaris.org static size_t col_dpy_prt_tofile[] = {
12611230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_nm),
12711230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_val)
12811230Sgdamore@opensolaris.org };
12911230Sgdamore@opensolaris.org 
13011230Sgdamore@opensolaris.org 
13111230Sgdamore@opensolaris.org /*
13211230Sgdamore@opensolaris.org  * mixer and control accounting
13311230Sgdamore@opensolaris.org  */
13411230Sgdamore@opensolaris.org 
13511230Sgdamore@opensolaris.org typedef struct cinfo {
13611230Sgdamore@opensolaris.org 	oss_mixext ci;
13711230Sgdamore@opensolaris.org 	oss_mixer_enuminfo *enump;
13811230Sgdamore@opensolaris.org } cinfo_t;
13911230Sgdamore@opensolaris.org 
14011230Sgdamore@opensolaris.org typedef struct device {
14111230Sgdamore@opensolaris.org 	oss_card_info	card;
14211230Sgdamore@opensolaris.org 	oss_mixerinfo	mixer;
14311230Sgdamore@opensolaris.org 
14411230Sgdamore@opensolaris.org 	int		cmax;
14511230Sgdamore@opensolaris.org 	cinfo_t		*controls;
14611230Sgdamore@opensolaris.org 
14711230Sgdamore@opensolaris.org 	int		mfd;
14811230Sgdamore@opensolaris.org 	dev_t		devt;
14911230Sgdamore@opensolaris.org 
15011230Sgdamore@opensolaris.org 	struct device	*nextp;
15111230Sgdamore@opensolaris.org } device_t;
15211230Sgdamore@opensolaris.org 
15311230Sgdamore@opensolaris.org static device_t	*devices = NULL;
15411230Sgdamore@opensolaris.org 
15511230Sgdamore@opensolaris.org /*PRINTFLIKE1*/
15611230Sgdamore@opensolaris.org static void
msg(char * fmt,...)15711230Sgdamore@opensolaris.org msg(char *fmt, ...)
15811230Sgdamore@opensolaris.org {
15911230Sgdamore@opensolaris.org 	va_list ap;
16011230Sgdamore@opensolaris.org 
16111230Sgdamore@opensolaris.org 	va_start(ap, fmt);
16211230Sgdamore@opensolaris.org 	(void) vprintf(fmt, ap);
16311230Sgdamore@opensolaris.org 	va_end(ap);
16411230Sgdamore@opensolaris.org }
16511230Sgdamore@opensolaris.org 
16611230Sgdamore@opensolaris.org /*PRINTFLIKE1*/
16711230Sgdamore@opensolaris.org static void
warn(char * fmt,...)16811230Sgdamore@opensolaris.org warn(char *fmt, ...)
16911230Sgdamore@opensolaris.org {
17011230Sgdamore@opensolaris.org 	va_list ap;
17111230Sgdamore@opensolaris.org 
17211230Sgdamore@opensolaris.org 	va_start(ap, fmt);
17311230Sgdamore@opensolaris.org 	(void) vfprintf(stderr, fmt, ap);
17411230Sgdamore@opensolaris.org 	va_end(ap);
17511230Sgdamore@opensolaris.org }
17611230Sgdamore@opensolaris.org 
17711230Sgdamore@opensolaris.org static void
free_device(device_t * d)17811230Sgdamore@opensolaris.org free_device(device_t *d)
17911230Sgdamore@opensolaris.org {
18011230Sgdamore@opensolaris.org 	int		i;
18111230Sgdamore@opensolaris.org 	device_t	**dpp;
18211230Sgdamore@opensolaris.org 
18311230Sgdamore@opensolaris.org 	dpp = &devices;
18411230Sgdamore@opensolaris.org 	while ((*dpp) && ((*dpp) != d)) {
18511230Sgdamore@opensolaris.org 		dpp = &((*dpp)->nextp);
18611230Sgdamore@opensolaris.org 	}
18711230Sgdamore@opensolaris.org 	if (*dpp) {
18811230Sgdamore@opensolaris.org 		*dpp = d->nextp;
18911230Sgdamore@opensolaris.org 	}
19011230Sgdamore@opensolaris.org 	for (i = 0; i < d->cmax; i++) {
19111230Sgdamore@opensolaris.org 		if (d->controls[i].enump != NULL)
19211230Sgdamore@opensolaris.org 			free(d->controls[i].enump);
19311230Sgdamore@opensolaris.org 	}
19411230Sgdamore@opensolaris.org 
19511230Sgdamore@opensolaris.org 	if (d->mfd >= 0)
19611230Sgdamore@opensolaris.org 		(void) close(d->mfd);
19711230Sgdamore@opensolaris.org 
19811230Sgdamore@opensolaris.org 	free(d);
19911230Sgdamore@opensolaris.org }
20011230Sgdamore@opensolaris.org 
20111230Sgdamore@opensolaris.org static void
free_devices(void)20211230Sgdamore@opensolaris.org free_devices(void)
20311230Sgdamore@opensolaris.org {
20411230Sgdamore@opensolaris.org 	device_t *d = devices;
20511230Sgdamore@opensolaris.org 
20611230Sgdamore@opensolaris.org 	while ((d = devices) != NULL) {
20711230Sgdamore@opensolaris.org 		free_device(d);
20811230Sgdamore@opensolaris.org 	}
20911230Sgdamore@opensolaris.org 
21011230Sgdamore@opensolaris.org 	devices = NULL;
21111230Sgdamore@opensolaris.org }
21211230Sgdamore@opensolaris.org 
21311230Sgdamore@opensolaris.org 
21411230Sgdamore@opensolaris.org /*
21511230Sgdamore@opensolaris.org  * adds to the end of global devices and returns a pointer to the new entry
21611230Sgdamore@opensolaris.org  */
21711230Sgdamore@opensolaris.org static device_t *
alloc_device(void)21811230Sgdamore@opensolaris.org alloc_device(void)
21911230Sgdamore@opensolaris.org {
22011230Sgdamore@opensolaris.org 	device_t *p;
22111230Sgdamore@opensolaris.org 	device_t *d = calloc(1, sizeof (*d));
22211230Sgdamore@opensolaris.org 
22311230Sgdamore@opensolaris.org 	d->card.card = -1;
22411230Sgdamore@opensolaris.org 	d->mixer.dev = -1;
22511230Sgdamore@opensolaris.org 	d->mfd = -1;
22611230Sgdamore@opensolaris.org 
22711230Sgdamore@opensolaris.org 	if (devices == NULL) {
22811230Sgdamore@opensolaris.org 		devices = d;
22911230Sgdamore@opensolaris.org 	} else {
23011230Sgdamore@opensolaris.org 		for (p = devices; p->nextp != NULL; p = p->nextp) {}
23111230Sgdamore@opensolaris.org 
23211230Sgdamore@opensolaris.org 		p->nextp = d;
23311230Sgdamore@opensolaris.org 	}
23411230Sgdamore@opensolaris.org 	return (d);
23511230Sgdamore@opensolaris.org }
23611230Sgdamore@opensolaris.org 
23711230Sgdamore@opensolaris.org 
23811230Sgdamore@opensolaris.org /*
23911230Sgdamore@opensolaris.org  * cinfop->enump needs to be present
24011230Sgdamore@opensolaris.org  * idx should be: >= 0 to < cinfop->ci.maxvalue
24111230Sgdamore@opensolaris.org  */
24211230Sgdamore@opensolaris.org static char *
get_enum_str(cinfo_t * cinfop,int idx)24311230Sgdamore@opensolaris.org get_enum_str(cinfo_t *cinfop, int idx)
24411230Sgdamore@opensolaris.org {
24511230Sgdamore@opensolaris.org 	int sz = sizeof (*cinfop->ci.enum_present) * 8;
24611230Sgdamore@opensolaris.org 
24711230Sgdamore@opensolaris.org 	if (cinfop->ci.enum_present[idx / sz] & (1 << (idx % sz)))
24811230Sgdamore@opensolaris.org 		return (cinfop->enump->strings + cinfop->enump->strindex[idx]);
24911230Sgdamore@opensolaris.org 
25011230Sgdamore@opensolaris.org 	return (NULL);
25111230Sgdamore@opensolaris.org }
25211230Sgdamore@opensolaris.org 
25311230Sgdamore@opensolaris.org 
25411230Sgdamore@opensolaris.org /*
25511230Sgdamore@opensolaris.org  * caller fills in d->mixer.devnode; func fills in the rest
25611230Sgdamore@opensolaris.org  */
25711230Sgdamore@opensolaris.org static int
get_device_info(device_t * d)25811230Sgdamore@opensolaris.org get_device_info(device_t *d)
25911230Sgdamore@opensolaris.org {
26011230Sgdamore@opensolaris.org 	int fd = -1;
26111230Sgdamore@opensolaris.org 	int i;
26211230Sgdamore@opensolaris.org 	cinfo_t *ci;
26311230Sgdamore@opensolaris.org 
26411230Sgdamore@opensolaris.org 	if ((fd = open(d->mixer.devnode, O_RDWR)) < 0) {
26511230Sgdamore@opensolaris.org 		perror(_("Error opening device"));
26611230Sgdamore@opensolaris.org 		return (errno);
26711230Sgdamore@opensolaris.org 	}
26811230Sgdamore@opensolaris.org 	d->mfd = fd;
26911230Sgdamore@opensolaris.org 
27011230Sgdamore@opensolaris.org 	d->cmax = -1;
27111230Sgdamore@opensolaris.org 	if (ioctl(fd, SNDCTL_MIX_NREXT, &d->cmax) < 0) {
27211230Sgdamore@opensolaris.org 		perror(_("Error getting control count"));
27311230Sgdamore@opensolaris.org 		return (errno);
27411230Sgdamore@opensolaris.org 	}
27511230Sgdamore@opensolaris.org 
27611230Sgdamore@opensolaris.org 	d->controls = calloc(d->cmax, sizeof (*d->controls));
27711230Sgdamore@opensolaris.org 
27811230Sgdamore@opensolaris.org 	for (i = 0; i < d->cmax; i++) {
27911230Sgdamore@opensolaris.org 		ci = &d->controls[i];
28011230Sgdamore@opensolaris.org 
28111230Sgdamore@opensolaris.org 		ci->ci.dev = -1;
28211230Sgdamore@opensolaris.org 		ci->ci.ctrl = i;
28311230Sgdamore@opensolaris.org 
28411230Sgdamore@opensolaris.org 		if (ioctl(fd, SNDCTL_MIX_EXTINFO, &ci->ci) < 0) {
28511230Sgdamore@opensolaris.org 			perror(_("Error getting control info"));
28611230Sgdamore@opensolaris.org 			return (errno);
28711230Sgdamore@opensolaris.org 		}
28811230Sgdamore@opensolaris.org 
28911230Sgdamore@opensolaris.org 		if (ci->ci.type == MIXT_ENUM) {
29011230Sgdamore@opensolaris.org 			ci->enump = calloc(1, sizeof (*ci->enump));
29111230Sgdamore@opensolaris.org 			ci->enump->dev = -1;
29211230Sgdamore@opensolaris.org 			ci->enump->ctrl = ci->ci.ctrl;
29311230Sgdamore@opensolaris.org 
29411230Sgdamore@opensolaris.org 			if (ioctl(fd, SNDCTL_MIX_ENUMINFO, ci->enump) < 0) {
29511230Sgdamore@opensolaris.org 				perror(_("Error getting enum info"));
29611230Sgdamore@opensolaris.org 				return (errno);
29711230Sgdamore@opensolaris.org 			}
29811230Sgdamore@opensolaris.org 		}
29911230Sgdamore@opensolaris.org 	}
30011230Sgdamore@opensolaris.org 
30111230Sgdamore@opensolaris.org 	return (0);
30211230Sgdamore@opensolaris.org }
30311230Sgdamore@opensolaris.org 
30411230Sgdamore@opensolaris.org 
30511230Sgdamore@opensolaris.org static int
load_devices(void)30611230Sgdamore@opensolaris.org load_devices(void)
30711230Sgdamore@opensolaris.org {
30811230Sgdamore@opensolaris.org 	int rv = -1;
30911230Sgdamore@opensolaris.org 	int fd = -1;
31011230Sgdamore@opensolaris.org 	int i;
31111230Sgdamore@opensolaris.org 	oss_sysinfo si;
31211230Sgdamore@opensolaris.org 	device_t *d;
31311230Sgdamore@opensolaris.org 
31411253Sgdamore@opensolaris.org 	if (devices != NULL) {
31511253Sgdamore@opensolaris.org 		/* already loaded */
31611253Sgdamore@opensolaris.org 		return (0);
31711253Sgdamore@opensolaris.org 	}
31811253Sgdamore@opensolaris.org 
31911230Sgdamore@opensolaris.org 	if ((fd = open("/dev/mixer", O_RDWR)) < 0) {
32011230Sgdamore@opensolaris.org 		rv = errno;
32111230Sgdamore@opensolaris.org 		warn(_("Error opening mixer\n"));
32211230Sgdamore@opensolaris.org 		goto OUT;
32311230Sgdamore@opensolaris.org 	}
32411230Sgdamore@opensolaris.org 
32511230Sgdamore@opensolaris.org 	if (ioctl(fd, SNDCTL_SYSINFO, &si) < 0) {
32611230Sgdamore@opensolaris.org 		rv = errno;
32711230Sgdamore@opensolaris.org 		perror(_("Error getting system information"));
32811230Sgdamore@opensolaris.org 		goto OUT;
32911230Sgdamore@opensolaris.org 	}
33011230Sgdamore@opensolaris.org 
33111230Sgdamore@opensolaris.org 	for (i = 0; i < si.nummixers; i++) {
33211230Sgdamore@opensolaris.org 
33311230Sgdamore@opensolaris.org 		struct stat sbuf;
33411230Sgdamore@opensolaris.org 
33511230Sgdamore@opensolaris.org 		d = alloc_device();
33611230Sgdamore@opensolaris.org 		d->mixer.dev = i;
33711230Sgdamore@opensolaris.org 
33811230Sgdamore@opensolaris.org 		if (ioctl(fd, SNDCTL_MIXERINFO, &d->mixer) != 0) {
33911230Sgdamore@opensolaris.org 			continue;
34011230Sgdamore@opensolaris.org 		}
34111230Sgdamore@opensolaris.org 
34211230Sgdamore@opensolaris.org 		d->card.card = d->mixer.card_number;
34311230Sgdamore@opensolaris.org 
34411230Sgdamore@opensolaris.org 		if ((ioctl(fd, SNDCTL_CARDINFO, &d->card) != 0) ||
34511230Sgdamore@opensolaris.org 		    (stat(d->mixer.devnode, &sbuf) != 0) ||
34611230Sgdamore@opensolaris.org 		    ((sbuf.st_mode & S_IFCHR) == 0)) {
34711230Sgdamore@opensolaris.org 			warn(_("Device present: %s\n"), d->mixer.devnode);
34811230Sgdamore@opensolaris.org 			free_device(d);
34911230Sgdamore@opensolaris.org 			continue;
35011230Sgdamore@opensolaris.org 		}
35111230Sgdamore@opensolaris.org 		d->devt = makedev(major(sbuf.st_rdev),
35211230Sgdamore@opensolaris.org 		    minor(sbuf.st_rdev) & ~(AUDIO_MN_TYPE_MASK));
35311230Sgdamore@opensolaris.org 
35411230Sgdamore@opensolaris.org 		if ((rv = get_device_info(d)) != 0) {
35511230Sgdamore@opensolaris.org 			free_device(d);
35611230Sgdamore@opensolaris.org 			goto OUT;
35711230Sgdamore@opensolaris.org 		}
35811230Sgdamore@opensolaris.org 	}
35911230Sgdamore@opensolaris.org 
36011230Sgdamore@opensolaris.org 	rv = 0;
36111230Sgdamore@opensolaris.org 
36211230Sgdamore@opensolaris.org OUT:
36311230Sgdamore@opensolaris.org 	if (fd >= 0)
36411230Sgdamore@opensolaris.org 		(void) close(fd);
36511230Sgdamore@opensolaris.org 	return (rv);
36611230Sgdamore@opensolaris.org }
36711230Sgdamore@opensolaris.org 
36811230Sgdamore@opensolaris.org 
36911230Sgdamore@opensolaris.org static int
ctype_valid(int type)37011230Sgdamore@opensolaris.org ctype_valid(int type)
37111230Sgdamore@opensolaris.org {
37211230Sgdamore@opensolaris.org 	switch (type) {
37311230Sgdamore@opensolaris.org 	case MIXT_ONOFF:
37411230Sgdamore@opensolaris.org 	case MIXT_ENUM:
37511230Sgdamore@opensolaris.org 	case MIXT_MONOSLIDER:
37611230Sgdamore@opensolaris.org 	case MIXT_STEREOSLIDER:
37711230Sgdamore@opensolaris.org 		return (1);
37811230Sgdamore@opensolaris.org 	default:
37911230Sgdamore@opensolaris.org 		return (0);
38011230Sgdamore@opensolaris.org 	}
38111230Sgdamore@opensolaris.org }
38211230Sgdamore@opensolaris.org 
38311230Sgdamore@opensolaris.org 
38411230Sgdamore@opensolaris.org static void
print_control_line(FILE * sfp,col_prt_t * colp,int vopt)38511230Sgdamore@opensolaris.org print_control_line(FILE *sfp, col_prt_t *colp, int vopt)
38611230Sgdamore@opensolaris.org {
38711230Sgdamore@opensolaris.org 	int i;
38811230Sgdamore@opensolaris.org 	size_t *col_prtp;
38911230Sgdamore@opensolaris.org 	int *col_dpyp;
39011230Sgdamore@opensolaris.org 	int col_cnt;
39111230Sgdamore@opensolaris.org 	int col_type;
39211230Sgdamore@opensolaris.org 	int width;
39311230Sgdamore@opensolaris.org 	char *colstr;
39411230Sgdamore@opensolaris.org 	char cbuf[COL_MAX_SZ + 1];
39511230Sgdamore@opensolaris.org 	char line[128];
39611230Sgdamore@opensolaris.org 	char *colsep =  " ";
39711230Sgdamore@opensolaris.org 
39811230Sgdamore@opensolaris.org 	if (sfp != NULL) {
39911230Sgdamore@opensolaris.org 		col_prtp = col_dpy_prt_tofile;
40011230Sgdamore@opensolaris.org 		col_dpyp = col_dpy_tofile;
40111230Sgdamore@opensolaris.org 		col_cnt = col_dpy_tofile_len;
40211230Sgdamore@opensolaris.org 	} else if (vopt) {
40311230Sgdamore@opensolaris.org 		col_prtp = col_dpy_prt_vopt;
40411230Sgdamore@opensolaris.org 		col_dpyp = col_dpy_vopt;
40511230Sgdamore@opensolaris.org 		col_cnt = col_dpy_vopt_len;
40611230Sgdamore@opensolaris.org 	} else {
40711230Sgdamore@opensolaris.org 		col_prtp = col_dpy_prt;
40811230Sgdamore@opensolaris.org 		col_dpyp = col_dpy;
40911230Sgdamore@opensolaris.org 		col_cnt = col_dpy_len;
41011230Sgdamore@opensolaris.org 	}
41111230Sgdamore@opensolaris.org 
41211230Sgdamore@opensolaris.org 	line[0] = '\0';
41311230Sgdamore@opensolaris.org 
41411230Sgdamore@opensolaris.org 	for (i = 0; i < col_cnt; i++) {
41511230Sgdamore@opensolaris.org 		col_type = col_dpyp[i];
41611230Sgdamore@opensolaris.org 		width = col_sz[col_type];
41711230Sgdamore@opensolaris.org 		colstr = *(char **)(((size_t)colp) + col_prtp[i]);
41811230Sgdamore@opensolaris.org 
41911230Sgdamore@opensolaris.org 		(void) snprintf(cbuf, sizeof (cbuf), "%- *s",
42011230Sgdamore@opensolaris.org 		    width > 0 ? width : 1,
42111230Sgdamore@opensolaris.org 		    (colstr == NULL) ? "" : colstr);
42211230Sgdamore@opensolaris.org 
42311230Sgdamore@opensolaris.org 		(void) strlcat(line, cbuf, sizeof (line));
42411230Sgdamore@opensolaris.org 		if (i < col_cnt - 1)
42511230Sgdamore@opensolaris.org 			(void) strlcat(line, colsep, sizeof (line));
42611230Sgdamore@opensolaris.org 	}
42711230Sgdamore@opensolaris.org 
42811230Sgdamore@opensolaris.org 	(void) fprintf(sfp ? sfp : stdout, "%s\n", line);
42911230Sgdamore@opensolaris.org }
43011230Sgdamore@opensolaris.org 
43111230Sgdamore@opensolaris.org 
43211230Sgdamore@opensolaris.org static void
print_header(FILE * sfp,int vopt)43311230Sgdamore@opensolaris.org print_header(FILE *sfp, int vopt)
43411230Sgdamore@opensolaris.org {
43511230Sgdamore@opensolaris.org 	col_prt_t col;
43611230Sgdamore@opensolaris.org 
43711230Sgdamore@opensolaris.org 	if (sfp) {
43811230Sgdamore@opensolaris.org 		col.col_nm = _("#CONTROL");
43911230Sgdamore@opensolaris.org 		col.col_val = _("VALUE");
44011230Sgdamore@opensolaris.org 	} else {
44111230Sgdamore@opensolaris.org 		col.col_dv = _("DEVICE");
44211230Sgdamore@opensolaris.org 		col.col_nm = _("CONTROL");
44311230Sgdamore@opensolaris.org 		col.col_val = _("VALUE");
44411230Sgdamore@opensolaris.org 		col.col_sel = _("POSSIBLE");
44511230Sgdamore@opensolaris.org 	}
44611230Sgdamore@opensolaris.org 	print_control_line(sfp, &col, vopt);
44711230Sgdamore@opensolaris.org }
44811230Sgdamore@opensolaris.org 
44911230Sgdamore@opensolaris.org 
45011230Sgdamore@opensolaris.org static int
print_control(FILE * sfp,device_t * d,cinfo_t * cinfop,int vopt)45111230Sgdamore@opensolaris.org print_control(FILE *sfp, device_t *d, cinfo_t *cinfop, int vopt)
45211230Sgdamore@opensolaris.org {
45311230Sgdamore@opensolaris.org 	int mfd = d->mfd;
45411230Sgdamore@opensolaris.org 	char *devnm = d->card.shortname;
45511230Sgdamore@opensolaris.org 	oss_mixer_value cval;
45611230Sgdamore@opensolaris.org 	char *str;
45711230Sgdamore@opensolaris.org 	int i;
45811230Sgdamore@opensolaris.org 	int idx = -1;
45911230Sgdamore@opensolaris.org 	int rv = -1;
46011230Sgdamore@opensolaris.org 	char valbuf[COL_VAL_SZ + 1];
46111230Sgdamore@opensolaris.org 	char selbuf[COL_SEL_SZ + 1];
46211230Sgdamore@opensolaris.org 	col_prt_t col;
46311230Sgdamore@opensolaris.org 
46411230Sgdamore@opensolaris.org 	cval.dev = -1;
46511230Sgdamore@opensolaris.org 	cval.ctrl = cinfop->ci.ctrl;
46611230Sgdamore@opensolaris.org 
46711230Sgdamore@opensolaris.org 	if (ctype_valid(cinfop->ci.type)) {
46811230Sgdamore@opensolaris.org 		if (ioctl(mfd, SNDCTL_MIX_READ, &cval) < 0) {
46911230Sgdamore@opensolaris.org 			rv = errno;
47011230Sgdamore@opensolaris.org 			perror(_("Error reading control\n"));
47111230Sgdamore@opensolaris.org 			return (rv);
47211230Sgdamore@opensolaris.org 		}
47311230Sgdamore@opensolaris.org 	} else {
47411230Sgdamore@opensolaris.org 		return (0);
47511230Sgdamore@opensolaris.org 	}
47611230Sgdamore@opensolaris.org 
47711230Sgdamore@opensolaris.org 	/*
47811230Sgdamore@opensolaris.org 	 * convert the control value into a string
47911230Sgdamore@opensolaris.org 	 */
48011230Sgdamore@opensolaris.org 	switch (cinfop->ci.type) {
48111230Sgdamore@opensolaris.org 	case MIXT_ONOFF:
48211230Sgdamore@opensolaris.org 		(void) snprintf(valbuf, sizeof (valbuf), "%s",
48311230Sgdamore@opensolaris.org 		    cval.value ? _("on") : _("off"));
48411230Sgdamore@opensolaris.org 		break;
48511230Sgdamore@opensolaris.org 
48611230Sgdamore@opensolaris.org 	case MIXT_MONOSLIDER:
48711230Sgdamore@opensolaris.org 		(void) snprintf(valbuf, sizeof (valbuf), "%d",
48811230Sgdamore@opensolaris.org 		    cval.value & 0xff);
48911230Sgdamore@opensolaris.org 		break;
49011230Sgdamore@opensolaris.org 
49111230Sgdamore@opensolaris.org 	case MIXT_STEREOSLIDER:
49211230Sgdamore@opensolaris.org 		(void) snprintf(valbuf, sizeof (valbuf), "%d:%d",
49311230Sgdamore@opensolaris.org 		    (int)AUDIO_CTRL_STEREO_LEFT(cval.value),
49411230Sgdamore@opensolaris.org 		    (int)AUDIO_CTRL_STEREO_RIGHT(cval.value));
49511230Sgdamore@opensolaris.org 		break;
49611230Sgdamore@opensolaris.org 
49711230Sgdamore@opensolaris.org 	case MIXT_ENUM:
49811230Sgdamore@opensolaris.org 		str = get_enum_str(cinfop, cval.value);
49911230Sgdamore@opensolaris.org 		if (str == NULL) {
50011230Sgdamore@opensolaris.org 			warn(_("Bad enum index %d for control '%s'\n"),
50111230Sgdamore@opensolaris.org 			    cval.value, cinfop->ci.extname);
50211230Sgdamore@opensolaris.org 			return (EINVAL);
50311230Sgdamore@opensolaris.org 		}
50411230Sgdamore@opensolaris.org 
50511230Sgdamore@opensolaris.org 		(void) snprintf(valbuf, sizeof (valbuf), "%s", str);
50611230Sgdamore@opensolaris.org 		break;
50711230Sgdamore@opensolaris.org 
50811230Sgdamore@opensolaris.org 	default:
50911230Sgdamore@opensolaris.org 		return (0);
51011230Sgdamore@opensolaris.org 	}
51111230Sgdamore@opensolaris.org 
51211230Sgdamore@opensolaris.org 	/*
51311230Sgdamore@opensolaris.org 	 * possible control values (range/selection)
51411230Sgdamore@opensolaris.org 	 */
51511230Sgdamore@opensolaris.org 	switch (cinfop->ci.type) {
51611230Sgdamore@opensolaris.org 	case MIXT_ONOFF:
51711230Sgdamore@opensolaris.org 		(void) snprintf(selbuf, sizeof (selbuf), _("on,off"));
51811230Sgdamore@opensolaris.org 		break;
51911230Sgdamore@opensolaris.org 
52011230Sgdamore@opensolaris.org 	case MIXT_MONOSLIDER:
52111230Sgdamore@opensolaris.org 		(void) snprintf(selbuf, sizeof (selbuf), "%d-%d",
52211230Sgdamore@opensolaris.org 		    cinfop->ci.minvalue, cinfop->ci.maxvalue);
52311230Sgdamore@opensolaris.org 		break;
52411230Sgdamore@opensolaris.org 	case MIXT_STEREOSLIDER:
52511230Sgdamore@opensolaris.org 		(void) snprintf(selbuf, sizeof (selbuf), "%d-%d:%d-%d",
52611230Sgdamore@opensolaris.org 		    cinfop->ci.minvalue, cinfop->ci.maxvalue,
52711230Sgdamore@opensolaris.org 		    cinfop->ci.minvalue, cinfop->ci.maxvalue);
52811230Sgdamore@opensolaris.org 		break;
52911230Sgdamore@opensolaris.org 
53011230Sgdamore@opensolaris.org 	case MIXT_ENUM:
53111230Sgdamore@opensolaris.org 		/*
53211230Sgdamore@opensolaris.org 		 * display the first choice on the same line, then display
53311230Sgdamore@opensolaris.org 		 * the rest on multiple lines
53411230Sgdamore@opensolaris.org 		 */
53511230Sgdamore@opensolaris.org 		selbuf[0] = 0;
53611230Sgdamore@opensolaris.org 		for (i = 0; i < cinfop->ci.maxvalue; i++) {
53711230Sgdamore@opensolaris.org 			str = get_enum_str(cinfop, i);
53811230Sgdamore@opensolaris.org 			if (str == NULL)
53911230Sgdamore@opensolaris.org 				continue;
54011230Sgdamore@opensolaris.org 
54111230Sgdamore@opensolaris.org 			if ((strlen(str) + 1 + strlen(selbuf)) >=
54211230Sgdamore@opensolaris.org 			    sizeof (selbuf)) {
54311230Sgdamore@opensolaris.org 				break;
54411230Sgdamore@opensolaris.org 			}
54511230Sgdamore@opensolaris.org 			if (strlen(selbuf)) {
54611230Sgdamore@opensolaris.org 				(void) strlcat(selbuf, ",", sizeof (selbuf));
54711230Sgdamore@opensolaris.org 			}
54811230Sgdamore@opensolaris.org 
54911230Sgdamore@opensolaris.org 			(void) strlcat(selbuf, str, sizeof (selbuf));
55011230Sgdamore@opensolaris.org 		}
55111230Sgdamore@opensolaris.org 		idx = i;
55211230Sgdamore@opensolaris.org 		break;
55311230Sgdamore@opensolaris.org 
55411230Sgdamore@opensolaris.org 	default:
55511230Sgdamore@opensolaris.org 		(void) snprintf(selbuf, sizeof (selbuf), "-");
55611230Sgdamore@opensolaris.org 	}
55711230Sgdamore@opensolaris.org 
55811230Sgdamore@opensolaris.org 	col.col_dv = devnm;
55911230Sgdamore@opensolaris.org 	col.col_nm = strlen(cinfop->ci.extname) ?
56011230Sgdamore@opensolaris.org 	    cinfop->ci.extname : cinfop->ci.id;
56111230Sgdamore@opensolaris.org 	while (strchr(col.col_nm, '_') != NULL) {
56211230Sgdamore@opensolaris.org 		col.col_nm = strchr(col.col_nm, '_') + 1;
56311230Sgdamore@opensolaris.org 	}
56411230Sgdamore@opensolaris.org 	col.col_val = valbuf;
56511230Sgdamore@opensolaris.org 	col.col_sel = selbuf;
56611230Sgdamore@opensolaris.org 	print_control_line(sfp, &col, vopt);
56711230Sgdamore@opensolaris.org 
568*11423Sgdamore@opensolaris.org 	/* non-verbose mode prints don't display the enum values */
569*11423Sgdamore@opensolaris.org 	if ((!vopt) || (sfp != NULL)) {
570*11423Sgdamore@opensolaris.org 		return (0);
571*11423Sgdamore@opensolaris.org 	}
572*11423Sgdamore@opensolaris.org 
57311230Sgdamore@opensolaris.org 	/* print leftover enum value selections */
574*11423Sgdamore@opensolaris.org 	while ((idx >= 0) && (idx < cinfop->ci.maxvalue)) {
57511230Sgdamore@opensolaris.org 		selbuf[0] = 0;
57611230Sgdamore@opensolaris.org 		for (i = idx; i < cinfop->ci.maxvalue; i++) {
57711230Sgdamore@opensolaris.org 			str = get_enum_str(cinfop, i);
57811230Sgdamore@opensolaris.org 			if (str == NULL)
57911230Sgdamore@opensolaris.org 				continue;
58011230Sgdamore@opensolaris.org 
58111230Sgdamore@opensolaris.org 			if ((strlen(str) + 1 + strlen(selbuf)) >=
58211230Sgdamore@opensolaris.org 			    sizeof (selbuf)) {
58311230Sgdamore@opensolaris.org 				break;
58411230Sgdamore@opensolaris.org 			}
58511230Sgdamore@opensolaris.org 			if (strlen(selbuf)) {
58611230Sgdamore@opensolaris.org 				(void) strlcat(selbuf, ",", sizeof (selbuf));
58711230Sgdamore@opensolaris.org 			}
58811230Sgdamore@opensolaris.org 
58911230Sgdamore@opensolaris.org 			(void) strlcat(selbuf, str, sizeof (selbuf));
59011230Sgdamore@opensolaris.org 		}
59111230Sgdamore@opensolaris.org 		idx = i;
59211230Sgdamore@opensolaris.org 		col.col_dv = NULL;
59311230Sgdamore@opensolaris.org 		col.col_nm = NULL;
59411230Sgdamore@opensolaris.org 		col.col_val = NULL;
59511230Sgdamore@opensolaris.org 		col.col_sel = selbuf;
59611230Sgdamore@opensolaris.org 		print_control_line(sfp, &col, vopt);
59711230Sgdamore@opensolaris.org 	}
59811230Sgdamore@opensolaris.org 
59911230Sgdamore@opensolaris.org 	return (0);
60011230Sgdamore@opensolaris.org }
60111230Sgdamore@opensolaris.org 
60211230Sgdamore@opensolaris.org 
60311230Sgdamore@opensolaris.org static int
set_device_control(device_t * d,cinfo_t * cinfop,char * wstr,int vopt)60411230Sgdamore@opensolaris.org set_device_control(device_t *d, cinfo_t *cinfop, char *wstr, int vopt)
60511230Sgdamore@opensolaris.org {
60611230Sgdamore@opensolaris.org 	int mfd = d->mfd;
60711230Sgdamore@opensolaris.org 	oss_mixer_value cval;
60811230Sgdamore@opensolaris.org 	int wlen = strlen(wstr);
60911230Sgdamore@opensolaris.org 	int lval, rval;
61011230Sgdamore@opensolaris.org 	char *lstr, *rstr;
61111230Sgdamore@opensolaris.org 	char *str;
61211230Sgdamore@opensolaris.org 	int i;
61311230Sgdamore@opensolaris.org 	int rv = -1;
61411230Sgdamore@opensolaris.org 
61511230Sgdamore@opensolaris.org 	cval.dev = -1;
61611230Sgdamore@opensolaris.org 	cval.ctrl = cinfop->ci.ctrl;
61711230Sgdamore@opensolaris.org 	cval.value = 0;
61811230Sgdamore@opensolaris.org 
61911230Sgdamore@opensolaris.org 	switch (cinfop->ci.type) {
62011230Sgdamore@opensolaris.org 	case MIXT_ONOFF:
62111230Sgdamore@opensolaris.org 		cval.value = (strncmp(_("on"), wstr, wlen) == 0) ? 1 : 0;
62211230Sgdamore@opensolaris.org 		break;
62311230Sgdamore@opensolaris.org 
62411230Sgdamore@opensolaris.org 	case MIXT_MONOSLIDER:
62511230Sgdamore@opensolaris.org 		cval.value = atoi(wstr);
62611230Sgdamore@opensolaris.org 		break;
62711230Sgdamore@opensolaris.org 
62811230Sgdamore@opensolaris.org 	case MIXT_STEREOSLIDER:
62911230Sgdamore@opensolaris.org 		lstr = wstr;
63011230Sgdamore@opensolaris.org 		rstr = strchr(wstr, ':');
63111230Sgdamore@opensolaris.org 		if (rstr != NULL) {
63211230Sgdamore@opensolaris.org 			*rstr = '\0';
63311230Sgdamore@opensolaris.org 			rstr++;
63411230Sgdamore@opensolaris.org 
63511230Sgdamore@opensolaris.org 			rval = atoi(rstr);
63611230Sgdamore@opensolaris.org 			lval = atoi(lstr);
63711230Sgdamore@opensolaris.org 
63811230Sgdamore@opensolaris.org 			rstr--;
63911230Sgdamore@opensolaris.org 			*rstr = ':';
64011230Sgdamore@opensolaris.org 		} else {
64111230Sgdamore@opensolaris.org 			lval = atoi(lstr);
64211230Sgdamore@opensolaris.org 			rval = lval;
64311230Sgdamore@opensolaris.org 		}
64411230Sgdamore@opensolaris.org 
64511230Sgdamore@opensolaris.org 		cval.value = AUDIO_CTRL_STEREO_VAL(lval, rval);
64611230Sgdamore@opensolaris.org 		break;
64711230Sgdamore@opensolaris.org 
64811230Sgdamore@opensolaris.org 	case MIXT_ENUM:
64911230Sgdamore@opensolaris.org 		for (i = 0; i < cinfop->ci.maxvalue; i++) {
65011230Sgdamore@opensolaris.org 			str = get_enum_str(cinfop, i);
65111230Sgdamore@opensolaris.org 			if (str == NULL)
65211230Sgdamore@opensolaris.org 				continue;
65311230Sgdamore@opensolaris.org 
65411230Sgdamore@opensolaris.org 			if (strncmp(wstr, str, wlen) == 0) {
65511230Sgdamore@opensolaris.org 				cval.value = i;
65611230Sgdamore@opensolaris.org 				break;
65711230Sgdamore@opensolaris.org 			}
65811230Sgdamore@opensolaris.org 		}
65911230Sgdamore@opensolaris.org 
66011230Sgdamore@opensolaris.org 		if (i >= cinfop->ci.maxvalue) {
66111230Sgdamore@opensolaris.org 			warn(_("Invalid enumeration value\n"));
66211230Sgdamore@opensolaris.org 			return (EINVAL);
66311230Sgdamore@opensolaris.org 		}
66411230Sgdamore@opensolaris.org 		break;
66511230Sgdamore@opensolaris.org 
66611230Sgdamore@opensolaris.org 	default:
66711230Sgdamore@opensolaris.org 		warn(_("Unsupported control type: %d\n"), cinfop->ci.type);
66811230Sgdamore@opensolaris.org 		return (EINVAL);
66911230Sgdamore@opensolaris.org 	}
67011230Sgdamore@opensolaris.org 
67111230Sgdamore@opensolaris.org 	if (vopt) {
67211230Sgdamore@opensolaris.org 		msg(_("%s: '%s' set to '%s'\n"), d->card.shortname,
67311230Sgdamore@opensolaris.org 		    cinfop->ci.extname, wstr);
67411230Sgdamore@opensolaris.org 	}
67511230Sgdamore@opensolaris.org 
67611230Sgdamore@opensolaris.org 	if (ioctl(mfd, SNDCTL_MIX_WRITE, &cval) < 0) {
67711230Sgdamore@opensolaris.org 		rv = errno;
67811230Sgdamore@opensolaris.org 		perror(_("Error writing control"));
67911230Sgdamore@opensolaris.org 		return (rv);
68011230Sgdamore@opensolaris.org 	}
68111230Sgdamore@opensolaris.org 
68211230Sgdamore@opensolaris.org 	rv = 0;
68311230Sgdamore@opensolaris.org 	return (rv);
68411230Sgdamore@opensolaris.org }
68511230Sgdamore@opensolaris.org 
68611230Sgdamore@opensolaris.org 
68711230Sgdamore@opensolaris.org static void
help(void)68811230Sgdamore@opensolaris.org help(void)
68911230Sgdamore@opensolaris.org {
69011230Sgdamore@opensolaris.org #define	HELP_STR	_(						\
69111230Sgdamore@opensolaris.org "audioctl list-devices\n"						\
69211230Sgdamore@opensolaris.org "	list all audio devices\n"					\
69311230Sgdamore@opensolaris.org "\n"									\
69411230Sgdamore@opensolaris.org "audioctl show-device [ -v ] [ -d <device> ]\n"				\
69511230Sgdamore@opensolaris.org "	display information about an audio device\n"			\
69611230Sgdamore@opensolaris.org "\n"									\
69711230Sgdamore@opensolaris.org "audioctl show-control [ -v ] [ -d <device> ] [ <control> ... ]\n"	\
69811230Sgdamore@opensolaris.org "	get the value of a specific control (all if not specified)\n"	\
69911230Sgdamore@opensolaris.org "\n"									\
70011230Sgdamore@opensolaris.org "audioctl set-control [ -v ] [ -d <device> ] <control> <value>\n"	\
70111230Sgdamore@opensolaris.org "	set the value of a specific control\n"				\
70211230Sgdamore@opensolaris.org "\n"									\
70311230Sgdamore@opensolaris.org "audioctl save-controls [ -d <device> ] [ -f ] <file>\n"		\
70411230Sgdamore@opensolaris.org "	save all control settings for the device to a file\n"		\
70511230Sgdamore@opensolaris.org "\n"									\
70611230Sgdamore@opensolaris.org "audioctl load-controls [ -d <device> ] <file>\n"			\
70711230Sgdamore@opensolaris.org "	restore previously saved control settings to device\n"		\
70811230Sgdamore@opensolaris.org "\n"									\
70911230Sgdamore@opensolaris.org "audioctl help\n"							\
71011230Sgdamore@opensolaris.org "	show this message.\n")
71111230Sgdamore@opensolaris.org 
71211230Sgdamore@opensolaris.org 	(void) fprintf(stderr, HELP_STR);
71311230Sgdamore@opensolaris.org }
71411230Sgdamore@opensolaris.org 
71511230Sgdamore@opensolaris.org dev_t
device_devt(char * name)71611230Sgdamore@opensolaris.org device_devt(char *name)
71711230Sgdamore@opensolaris.org {
71811230Sgdamore@opensolaris.org 	struct stat	sbuf;
71911230Sgdamore@opensolaris.org 
72011230Sgdamore@opensolaris.org 	if ((stat(name, &sbuf) != 0) ||
72111230Sgdamore@opensolaris.org 	    ((sbuf.st_mode & S_IFCHR) == 0)) {
72211230Sgdamore@opensolaris.org 		/* Not a device node! */
72311230Sgdamore@opensolaris.org 		return (0);
72411230Sgdamore@opensolaris.org 	}
72511230Sgdamore@opensolaris.org 
72611230Sgdamore@opensolaris.org 	return (makedev(major(sbuf.st_rdev),
72711230Sgdamore@opensolaris.org 	    minor(sbuf.st_rdev) & ~(AUDIO_MN_TYPE_MASK)));
72811230Sgdamore@opensolaris.org }
72911230Sgdamore@opensolaris.org 
73011230Sgdamore@opensolaris.org static device_t *
find_device(char * name)73111230Sgdamore@opensolaris.org find_device(char *name)
73211230Sgdamore@opensolaris.org {
73311230Sgdamore@opensolaris.org 	dev_t		devt;
73411230Sgdamore@opensolaris.org 	device_t	*d;
73511230Sgdamore@opensolaris.org 
73611230Sgdamore@opensolaris.org 	/*
73711230Sgdamore@opensolaris.org 	 * User may have specified:
73811230Sgdamore@opensolaris.org 	 *
73911230Sgdamore@opensolaris.org 	 * /dev/dsp[<num>]
74011230Sgdamore@opensolaris.org 	 * /dev/mixer[<num>]
74111230Sgdamore@opensolaris.org 	 * /dev/audio[<num>9]
74211230Sgdamore@opensolaris.org 	 * /dev/audioctl[<num>]
74311230Sgdamore@opensolaris.org 	 * /dev/sound/<num>{,ctl,dsp,mixer}
74411230Sgdamore@opensolaris.org 	 * /dev/sound/<driver>:<num>{,ctl,dsp,mixer}
74511230Sgdamore@opensolaris.org 	 *
74611230Sgdamore@opensolaris.org 	 * We can canonicalize these by looking at the dev_t though.
74711230Sgdamore@opensolaris.org 	 */
74811230Sgdamore@opensolaris.org 
74911253Sgdamore@opensolaris.org 	if (load_devices() != 0) {
75011253Sgdamore@opensolaris.org 		return (NULL);
75111253Sgdamore@opensolaris.org 	}
75211253Sgdamore@opensolaris.org 
75311230Sgdamore@opensolaris.org 	if (name == NULL)
75411230Sgdamore@opensolaris.org 		name = getenv("AUDIODEV");
75511230Sgdamore@opensolaris.org 
75611230Sgdamore@opensolaris.org 	if ((name == NULL) ||
75711230Sgdamore@opensolaris.org 	    (strcmp(name, "/dev/mixer") == 0)) {
75811230Sgdamore@opensolaris.org 		/* /dev/mixer node doesn't point to real hw */
75911230Sgdamore@opensolaris.org 		name = "/dev/dsp";
76011230Sgdamore@opensolaris.org 	}
76111230Sgdamore@opensolaris.org 
76211230Sgdamore@opensolaris.org 	if (*name == '/') {
76311230Sgdamore@opensolaris.org 		/* if we have a full path, convert to the devt */
76411230Sgdamore@opensolaris.org 		if ((devt = device_devt(name)) == 0) {
76511230Sgdamore@opensolaris.org 			warn(_("No such audio device.\n"));
76611230Sgdamore@opensolaris.org 			return (NULL);
76711230Sgdamore@opensolaris.org 		}
76811230Sgdamore@opensolaris.org 		name = NULL;
76911230Sgdamore@opensolaris.org 	}
77011230Sgdamore@opensolaris.org 
77111230Sgdamore@opensolaris.org 	for (d = devices; d != NULL; d = d->nextp) {
77211230Sgdamore@opensolaris.org 		oss_card_info *card = &d->card;
77311230Sgdamore@opensolaris.org 
77411230Sgdamore@opensolaris.org 		if ((name) && (strcmp(name, card->shortname) == 0)) {
77511230Sgdamore@opensolaris.org 			return (d);
77611230Sgdamore@opensolaris.org 		}
77711230Sgdamore@opensolaris.org 		if (devt == d->devt) {
77811230Sgdamore@opensolaris.org 			return (d);
77911230Sgdamore@opensolaris.org 		}
78011230Sgdamore@opensolaris.org 	}
78111230Sgdamore@opensolaris.org 
78211230Sgdamore@opensolaris.org 	warn(_("No such audio device.\n"));
78311230Sgdamore@opensolaris.org 	return (NULL);
78411230Sgdamore@opensolaris.org }
78511230Sgdamore@opensolaris.org 
78611230Sgdamore@opensolaris.org int
do_list_devices(int argc,char ** argv)78711230Sgdamore@opensolaris.org do_list_devices(int argc, char **argv)
78811230Sgdamore@opensolaris.org {
78911230Sgdamore@opensolaris.org 	int		optc;
79011230Sgdamore@opensolaris.org 	int		verbose = 0;
79111230Sgdamore@opensolaris.org 	device_t	*d;
79211230Sgdamore@opensolaris.org 
79311230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "v")) != EOF) {
79411230Sgdamore@opensolaris.org 		switch (optc) {
79511230Sgdamore@opensolaris.org 		case 'v':
79611230Sgdamore@opensolaris.org 			verbose++;
79711230Sgdamore@opensolaris.org 			break;
79811230Sgdamore@opensolaris.org 		default:
79911230Sgdamore@opensolaris.org 			help();
80011230Sgdamore@opensolaris.org 			return (-1);
80111230Sgdamore@opensolaris.org 		}
80211230Sgdamore@opensolaris.org 	}
80311230Sgdamore@opensolaris.org 	argc -= optind;
80411230Sgdamore@opensolaris.org 	argv += optind;
80511230Sgdamore@opensolaris.org 	if (argc != 0) {
80611230Sgdamore@opensolaris.org 		help();
80711230Sgdamore@opensolaris.org 		return (-1);
80811230Sgdamore@opensolaris.org 	}
80911230Sgdamore@opensolaris.org 
81011253Sgdamore@opensolaris.org 	if (load_devices() != 0) {
81111253Sgdamore@opensolaris.org 		return (-1);
81211253Sgdamore@opensolaris.org 	}
81311253Sgdamore@opensolaris.org 
81411230Sgdamore@opensolaris.org 	for (d = devices; d != NULL; d = d->nextp) {
81511230Sgdamore@opensolaris.org 
81611230Sgdamore@opensolaris.org 		if ((d->mixer.enabled == 0) && (!verbose))
81711230Sgdamore@opensolaris.org 			continue;
81811230Sgdamore@opensolaris.org 
81911230Sgdamore@opensolaris.org 		if (verbose) {
82011230Sgdamore@opensolaris.org 			msg(_("%s (%s)\n"), d->card.shortname,
82111230Sgdamore@opensolaris.org 			    d->mixer.devnode);
82211230Sgdamore@opensolaris.org 		} else {
82311230Sgdamore@opensolaris.org 			msg(_("%s\n"), d->card.shortname);
82411230Sgdamore@opensolaris.org 		}
82511230Sgdamore@opensolaris.org 	}
82611230Sgdamore@opensolaris.org 
82711230Sgdamore@opensolaris.org 	return (0);
82811230Sgdamore@opensolaris.org }
82911230Sgdamore@opensolaris.org 
83011230Sgdamore@opensolaris.org int
do_show_device(int argc,char ** argv)83111230Sgdamore@opensolaris.org do_show_device(int argc, char **argv)
83211230Sgdamore@opensolaris.org {
83311230Sgdamore@opensolaris.org 	int		optc;
83411230Sgdamore@opensolaris.org 	char		*devname = NULL;
83511230Sgdamore@opensolaris.org 	device_t	*d;
83611230Sgdamore@opensolaris.org 
83711230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:v")) != EOF) {
83811230Sgdamore@opensolaris.org 		switch (optc) {
83911230Sgdamore@opensolaris.org 		case 'd':
84011230Sgdamore@opensolaris.org 			devname = optarg;
84111230Sgdamore@opensolaris.org 			break;
84211230Sgdamore@opensolaris.org 		case 'v':
84311230Sgdamore@opensolaris.org 			break;
84411230Sgdamore@opensolaris.org 		default:
84511230Sgdamore@opensolaris.org 			help();
84611230Sgdamore@opensolaris.org 			return (-1);
84711230Sgdamore@opensolaris.org 		}
84811230Sgdamore@opensolaris.org 	}
84911230Sgdamore@opensolaris.org 	argc -= optind;
85011230Sgdamore@opensolaris.org 	argv += optind;
85111230Sgdamore@opensolaris.org 	if (argc != 0) {
85211230Sgdamore@opensolaris.org 		help();
85311230Sgdamore@opensolaris.org 		return (-1);
85411230Sgdamore@opensolaris.org 	}
85511230Sgdamore@opensolaris.org 
85611230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
85711230Sgdamore@opensolaris.org 		return (ENODEV);
85811230Sgdamore@opensolaris.org 	}
85911230Sgdamore@opensolaris.org 
86011230Sgdamore@opensolaris.org 	msg(_("Device: %s\n"), d->mixer.devnode);
86111230Sgdamore@opensolaris.org 	msg(_("  Name    = %s\n"), d->card.shortname);
86211230Sgdamore@opensolaris.org 	msg(_("  Config  = %s\n"), d->card.longname);
86311230Sgdamore@opensolaris.org 
86411230Sgdamore@opensolaris.org 	if (strlen(d->card.hw_info)) {
86511230Sgdamore@opensolaris.org 		msg(_("  HW Info = %s"), d->card.hw_info);
86611230Sgdamore@opensolaris.org 	}
86711230Sgdamore@opensolaris.org 
86811230Sgdamore@opensolaris.org 	return (0);
86911230Sgdamore@opensolaris.org }
87011230Sgdamore@opensolaris.org 
87111230Sgdamore@opensolaris.org int
do_show_control(int argc,char ** argv)87211230Sgdamore@opensolaris.org do_show_control(int argc, char **argv)
87311230Sgdamore@opensolaris.org {
87411230Sgdamore@opensolaris.org 	int		optc;
87511230Sgdamore@opensolaris.org 	int		rval = 0;
87611230Sgdamore@opensolaris.org 	int		verbose = 0;
87711230Sgdamore@opensolaris.org 	device_t	*d;
87811230Sgdamore@opensolaris.org 	char		*devname = NULL;
87911230Sgdamore@opensolaris.org 	int		i;
88011230Sgdamore@opensolaris.org 	int		j;
88111230Sgdamore@opensolaris.org 	int		rv;
88211230Sgdamore@opensolaris.org 	char		*n;
88311230Sgdamore@opensolaris.org 	cinfo_t		*cinfop;
88411230Sgdamore@opensolaris.org 
88511230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:v")) != EOF) {
88611230Sgdamore@opensolaris.org 		switch (optc) {
88711230Sgdamore@opensolaris.org 		case 'd':
88811230Sgdamore@opensolaris.org 			devname = optarg;
88911230Sgdamore@opensolaris.org 			break;
89011230Sgdamore@opensolaris.org 		case 'v':
89111230Sgdamore@opensolaris.org 			verbose++;
89211230Sgdamore@opensolaris.org 			break;
89311230Sgdamore@opensolaris.org 		default:
89411230Sgdamore@opensolaris.org 			help();
89511230Sgdamore@opensolaris.org 			return (-1);
89611230Sgdamore@opensolaris.org 		}
89711230Sgdamore@opensolaris.org 	}
89811230Sgdamore@opensolaris.org 	argc -= optind;
89911230Sgdamore@opensolaris.org 	argv += optind;
90011230Sgdamore@opensolaris.org 
90111230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
90211230Sgdamore@opensolaris.org 		return (ENODEV);
90311230Sgdamore@opensolaris.org 	}
90411230Sgdamore@opensolaris.org 
90511230Sgdamore@opensolaris.org 	print_header(NULL, verbose);
90611230Sgdamore@opensolaris.org 	if (argc == 0) {
90711230Sgdamore@opensolaris.org 		/* do them all! */
90811230Sgdamore@opensolaris.org 		for (i = 0; i < d->cmax; i++) {
90911230Sgdamore@opensolaris.org 
91011230Sgdamore@opensolaris.org 			cinfop = &d->controls[i];
91111230Sgdamore@opensolaris.org 			rv = print_control(NULL, d, cinfop, verbose);
91211230Sgdamore@opensolaris.org 			rval = rval ? rval : rv;
91311230Sgdamore@opensolaris.org 		}
91411230Sgdamore@opensolaris.org 		return (rval);
91511230Sgdamore@opensolaris.org 	}
91611230Sgdamore@opensolaris.org 
91711230Sgdamore@opensolaris.org 	for (i = 0; i < argc; i++) {
91811230Sgdamore@opensolaris.org 		for (j = 0; j < d->cmax; j++) {
91911230Sgdamore@opensolaris.org 			cinfop = &d->controls[j];
92011230Sgdamore@opensolaris.org 			n = strrchr(cinfop->ci.extname, '_');
92111230Sgdamore@opensolaris.org 			n = n ? n + 1 : cinfop->ci.extname;
92211230Sgdamore@opensolaris.org 			if (strcmp(argv[i], n) == 0) {
92311230Sgdamore@opensolaris.org 				rv = print_control(NULL, d, cinfop, verbose);
92411230Sgdamore@opensolaris.org 				rval = rval ? rval : rv;
92511230Sgdamore@opensolaris.org 				break;
92611230Sgdamore@opensolaris.org 			}
92711230Sgdamore@opensolaris.org 		}
92811230Sgdamore@opensolaris.org 		/* Didn't find requested control */
92911230Sgdamore@opensolaris.org 		if (j == d->cmax) {
93011230Sgdamore@opensolaris.org 			warn(_("No such control: %s\n"), argv[i]);
93111230Sgdamore@opensolaris.org 			rval = rval ? rval : ENODEV;
93211230Sgdamore@opensolaris.org 		}
93311230Sgdamore@opensolaris.org 	}
93411230Sgdamore@opensolaris.org 
93511230Sgdamore@opensolaris.org 	return (rval);
93611230Sgdamore@opensolaris.org }
93711230Sgdamore@opensolaris.org 
93811230Sgdamore@opensolaris.org int
do_set_control(int argc,char ** argv)93911230Sgdamore@opensolaris.org do_set_control(int argc, char **argv)
94011230Sgdamore@opensolaris.org {
94111230Sgdamore@opensolaris.org 	int		optc;
94211230Sgdamore@opensolaris.org 	int		rval = 0;
94311230Sgdamore@opensolaris.org 	int		verbose = 0;
94411230Sgdamore@opensolaris.org 	device_t	*d;
94511230Sgdamore@opensolaris.org 	char		*devname = NULL;
94611230Sgdamore@opensolaris.org 	char		*cname;
94711230Sgdamore@opensolaris.org 	char		*value;
94811230Sgdamore@opensolaris.org 	int		i;
94911230Sgdamore@opensolaris.org 	int		found;
95011230Sgdamore@opensolaris.org 	int		rv;
95111230Sgdamore@opensolaris.org 	char		*n;
95211230Sgdamore@opensolaris.org 	cinfo_t		*cinfop;
95311230Sgdamore@opensolaris.org 
95411230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:v")) != EOF) {
95511230Sgdamore@opensolaris.org 		switch (optc) {
95611230Sgdamore@opensolaris.org 		case 'd':
95711230Sgdamore@opensolaris.org 			devname = optarg;
95811230Sgdamore@opensolaris.org 			break;
95911230Sgdamore@opensolaris.org 		case 'v':
96011230Sgdamore@opensolaris.org 			verbose = 1;
96111230Sgdamore@opensolaris.org 			break;
96211230Sgdamore@opensolaris.org 		default:
96311230Sgdamore@opensolaris.org 			help();
96411230Sgdamore@opensolaris.org 			return (-1);
96511230Sgdamore@opensolaris.org 		}
96611230Sgdamore@opensolaris.org 	}
96711230Sgdamore@opensolaris.org 	argc -= optind;
96811230Sgdamore@opensolaris.org 	argv += optind;
96911230Sgdamore@opensolaris.org 
97011230Sgdamore@opensolaris.org 	if (argc != 2) {
97111230Sgdamore@opensolaris.org 		help();
97211230Sgdamore@opensolaris.org 		return (-1);
97311230Sgdamore@opensolaris.org 	}
97411230Sgdamore@opensolaris.org 	cname = argv[0];
97511230Sgdamore@opensolaris.org 	value = argv[1];
97611230Sgdamore@opensolaris.org 
97711230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
97811230Sgdamore@opensolaris.org 		return (ENODEV);
97911230Sgdamore@opensolaris.org 	}
98011230Sgdamore@opensolaris.org 
98111230Sgdamore@opensolaris.org 	for (i = 0, found = 0; i < d->cmax; i++) {
98211230Sgdamore@opensolaris.org 		cinfop = &d->controls[i];
98311230Sgdamore@opensolaris.org 		n = strrchr(cinfop->ci.extname, '_');
98411230Sgdamore@opensolaris.org 		n = n ? n + 1 : cinfop->ci.extname;
98511230Sgdamore@opensolaris.org 		if (strcmp(cname, n) != 0) {
98611230Sgdamore@opensolaris.org 			continue;
98711230Sgdamore@opensolaris.org 		}
98811230Sgdamore@opensolaris.org 		found = 1;
98911230Sgdamore@opensolaris.org 		rv = set_device_control(d, cinfop, value, verbose);
99011230Sgdamore@opensolaris.org 		rval = rval ? rval : rv;
99111230Sgdamore@opensolaris.org 	}
99211230Sgdamore@opensolaris.org 	if (!found) {
99311230Sgdamore@opensolaris.org 		warn(_("No such control: %s\n"), cname);
99411230Sgdamore@opensolaris.org 	}
99511230Sgdamore@opensolaris.org 
99611230Sgdamore@opensolaris.org 	return (rval);
99711230Sgdamore@opensolaris.org }
99811230Sgdamore@opensolaris.org 
99911230Sgdamore@opensolaris.org int
do_save_controls(int argc,char ** argv)100011230Sgdamore@opensolaris.org do_save_controls(int argc, char **argv)
100111230Sgdamore@opensolaris.org {
100211230Sgdamore@opensolaris.org 	int		optc;
100311230Sgdamore@opensolaris.org 	int		rval = 0;
100411230Sgdamore@opensolaris.org 	device_t	*d;
100511230Sgdamore@opensolaris.org 	char		*devname = NULL;
100611230Sgdamore@opensolaris.org 	char		*fname;
100711230Sgdamore@opensolaris.org 	int		i;
100811230Sgdamore@opensolaris.org 	int		rv;
100911230Sgdamore@opensolaris.org 	cinfo_t		*cinfop;
101011230Sgdamore@opensolaris.org 	FILE		*fp;
101111230Sgdamore@opensolaris.org 	int		fd;
101211230Sgdamore@opensolaris.org 	int		mode;
101311230Sgdamore@opensolaris.org 
101411230Sgdamore@opensolaris.org 	mode = O_WRONLY | O_CREAT | O_EXCL;
101511230Sgdamore@opensolaris.org 
101611230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:f")) != EOF) {
101711230Sgdamore@opensolaris.org 		switch (optc) {
101811230Sgdamore@opensolaris.org 		case 'd':
101911230Sgdamore@opensolaris.org 			devname = optarg;
102011230Sgdamore@opensolaris.org 			break;
102111230Sgdamore@opensolaris.org 		case 'f':
102211230Sgdamore@opensolaris.org 			mode &= ~O_EXCL;
102311230Sgdamore@opensolaris.org 			mode |= O_TRUNC;
102411230Sgdamore@opensolaris.org 			break;
102511230Sgdamore@opensolaris.org 		default:
102611230Sgdamore@opensolaris.org 			help();
102711230Sgdamore@opensolaris.org 			return (-1);
102811230Sgdamore@opensolaris.org 		}
102911230Sgdamore@opensolaris.org 	}
103011230Sgdamore@opensolaris.org 	argc -= optind;
103111230Sgdamore@opensolaris.org 	argv += optind;
103211230Sgdamore@opensolaris.org 
103311230Sgdamore@opensolaris.org 	if (argc != 1) {
103411230Sgdamore@opensolaris.org 		help();
103511230Sgdamore@opensolaris.org 		return (-1);
103611230Sgdamore@opensolaris.org 	}
103711230Sgdamore@opensolaris.org 	fname = argv[0];
103811230Sgdamore@opensolaris.org 
103911230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
104011230Sgdamore@opensolaris.org 		return (ENODEV);
104111230Sgdamore@opensolaris.org 	}
104211230Sgdamore@opensolaris.org 
104311230Sgdamore@opensolaris.org 	if ((fd = open(fname, mode, 0666)) < 0) {
104411230Sgdamore@opensolaris.org 		perror(_("Failed to create file"));
104511230Sgdamore@opensolaris.org 		return (errno);
104611230Sgdamore@opensolaris.org 	}
104711230Sgdamore@opensolaris.org 
104811230Sgdamore@opensolaris.org 	if ((fp = fdopen(fd, "w")) == NULL) {
104911230Sgdamore@opensolaris.org 		perror(_("Unable to open file\n"));
105011230Sgdamore@opensolaris.org 		(void) close(fd);
105111230Sgdamore@opensolaris.org 		(void) unlink(fname);
105211230Sgdamore@opensolaris.org 		return (errno);
105311230Sgdamore@opensolaris.org 	}
105411230Sgdamore@opensolaris.org 
105511230Sgdamore@opensolaris.org 	(void) fprintf(fp, "# Device: %s\n", d->mixer.devnode);
105611230Sgdamore@opensolaris.org 	(void) fprintf(fp, "# Name    = %s\n", d->card.shortname);
105711230Sgdamore@opensolaris.org 	(void) fprintf(fp, "# Config  = %s\n", d->card.longname);
105811230Sgdamore@opensolaris.org 
105911230Sgdamore@opensolaris.org 	if (strlen(d->card.hw_info)) {
106011230Sgdamore@opensolaris.org 		(void) fprintf(fp, "# HW Info = %s", d->card.hw_info);
106111230Sgdamore@opensolaris.org 	}
106211230Sgdamore@opensolaris.org 	(void) fprintf(fp, "#\n");
106311230Sgdamore@opensolaris.org 
106411230Sgdamore@opensolaris.org 	print_header(fp, 0);
106511230Sgdamore@opensolaris.org 
106611230Sgdamore@opensolaris.org 	for (i = 0; i < d->cmax; i++) {
106711230Sgdamore@opensolaris.org 		cinfop = &d->controls[i];
106811230Sgdamore@opensolaris.org 		rv = print_control(fp, d, cinfop, 0);
106911230Sgdamore@opensolaris.org 		rval = rval ? rval : rv;
107011230Sgdamore@opensolaris.org 	}
107111230Sgdamore@opensolaris.org 
107211230Sgdamore@opensolaris.org 	(void) fclose(fp);
107311230Sgdamore@opensolaris.org 
107411230Sgdamore@opensolaris.org 	return (rval);
107511230Sgdamore@opensolaris.org }
107611230Sgdamore@opensolaris.org 
107711230Sgdamore@opensolaris.org int
do_load_controls(int argc,char ** argv)107811230Sgdamore@opensolaris.org do_load_controls(int argc, char **argv)
107911230Sgdamore@opensolaris.org {
108011230Sgdamore@opensolaris.org 	int	optc;
108111230Sgdamore@opensolaris.org 	int	rval = 0;
108211230Sgdamore@opensolaris.org 	device_t	*d;
108311230Sgdamore@opensolaris.org 	char		*devname = NULL;
108411230Sgdamore@opensolaris.org 	char	*fname;
108511230Sgdamore@opensolaris.org 	char	*cname;
108611230Sgdamore@opensolaris.org 	char	*value;
108711230Sgdamore@opensolaris.org 	int	i;
108811230Sgdamore@opensolaris.org 	int	rv;
108911230Sgdamore@opensolaris.org 	cinfo_t	*cinfop;
109011230Sgdamore@opensolaris.org 	FILE	*fp;
109111230Sgdamore@opensolaris.org 	char	linebuf[MAXLINE];
109211230Sgdamore@opensolaris.org 	int	lineno = 0;
109311230Sgdamore@opensolaris.org 	int	found;
109411230Sgdamore@opensolaris.org 
109511230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:")) != EOF) {
109611230Sgdamore@opensolaris.org 		switch (optc) {
109711230Sgdamore@opensolaris.org 		case 'd':
109811230Sgdamore@opensolaris.org 			devname = optarg;
109911230Sgdamore@opensolaris.org 			break;
110011230Sgdamore@opensolaris.org 		default:
110111230Sgdamore@opensolaris.org 			help();
110211230Sgdamore@opensolaris.org 			return (-1);
110311230Sgdamore@opensolaris.org 		}
110411230Sgdamore@opensolaris.org 	}
110511230Sgdamore@opensolaris.org 	argc -= optind;
110611230Sgdamore@opensolaris.org 	argv += optind;
110711230Sgdamore@opensolaris.org 
110811230Sgdamore@opensolaris.org 	if (argc != 1) {
110911230Sgdamore@opensolaris.org 		help();
111011230Sgdamore@opensolaris.org 		return (-1);
111111230Sgdamore@opensolaris.org 	}
111211230Sgdamore@opensolaris.org 	fname = argv[0];
111311230Sgdamore@opensolaris.org 
111411230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
111511230Sgdamore@opensolaris.org 		return (ENODEV);
111611230Sgdamore@opensolaris.org 	}
111711230Sgdamore@opensolaris.org 
111811230Sgdamore@opensolaris.org 	if ((fp = fopen(fname, "r")) == NULL) {
111911230Sgdamore@opensolaris.org 		perror(_("Unable to open file"));
112011230Sgdamore@opensolaris.org 		return (errno);
112111230Sgdamore@opensolaris.org 	}
112211230Sgdamore@opensolaris.org 
112311230Sgdamore@opensolaris.org 	while (fgets(linebuf, sizeof (linebuf), fp) != NULL) {
112411230Sgdamore@opensolaris.org 		lineno++;
112511230Sgdamore@opensolaris.org 		if (linebuf[strlen(linebuf) - 1] != '\n') {
112611230Sgdamore@opensolaris.org 			warn(_("Warning: line too long at line %d\n"), lineno);
112711230Sgdamore@opensolaris.org 			/* read in the rest of the line and discard it */
112811230Sgdamore@opensolaris.org 			while (fgets(linebuf, sizeof (linebuf), fp) != NULL &&
112911230Sgdamore@opensolaris.org 			    (linebuf[strlen(linebuf) - 1] != '\n')) {
113011230Sgdamore@opensolaris.org 				continue;
113111230Sgdamore@opensolaris.org 			}
113211230Sgdamore@opensolaris.org 			continue;
113311230Sgdamore@opensolaris.org 		}
113411230Sgdamore@opensolaris.org 
113511230Sgdamore@opensolaris.org 		/* we have a good line ... */
113611230Sgdamore@opensolaris.org 		cname = strtok(linebuf, " \t\n");
113711230Sgdamore@opensolaris.org 		/* skip comments and blank lines */
113811230Sgdamore@opensolaris.org 		if ((cname == NULL) || (cname[0] == '#')) {
113911230Sgdamore@opensolaris.org 			continue;
114011230Sgdamore@opensolaris.org 		}
114111230Sgdamore@opensolaris.org 		value = strtok(NULL, " \t\n");
114211230Sgdamore@opensolaris.org 		if ((value == NULL) || (*cname == 0)) {
114311230Sgdamore@opensolaris.org 			warn(_("Warning: missing value at line %d\n"), lineno);
114411230Sgdamore@opensolaris.org 			continue;
114511230Sgdamore@opensolaris.org 		}
114611230Sgdamore@opensolaris.org 
114711230Sgdamore@opensolaris.org 		for (i = 0, found = 0; i < d->cmax; i++) {
114811230Sgdamore@opensolaris.org 			/* save and restore requires an exact match */
114911230Sgdamore@opensolaris.org 			cinfop = &d->controls[i];
115011230Sgdamore@opensolaris.org 			if (strcmp(cinfop->ci.extname, cname) != 0) {
115111230Sgdamore@opensolaris.org 				continue;
115211230Sgdamore@opensolaris.org 			}
115311230Sgdamore@opensolaris.org 			found = 1;
115411230Sgdamore@opensolaris.org 			rv = set_device_control(d, cinfop, value, 0);
115511230Sgdamore@opensolaris.org 			rval = rval ? rval : rv;
115611230Sgdamore@opensolaris.org 		}
115711230Sgdamore@opensolaris.org 		if (!found) {
115811230Sgdamore@opensolaris.org 			warn(_("No such control: %s\n"), cname);
115911230Sgdamore@opensolaris.org 		}
116011230Sgdamore@opensolaris.org 	}
116111230Sgdamore@opensolaris.org 	(void) fclose(fp);
116211230Sgdamore@opensolaris.org 
116311230Sgdamore@opensolaris.org 	return (rval);
116411230Sgdamore@opensolaris.org }
116511230Sgdamore@opensolaris.org 
116611230Sgdamore@opensolaris.org int
mixer_walker(di_devlink_t dlink,void * arg)116711253Sgdamore@opensolaris.org mixer_walker(di_devlink_t dlink, void *arg)
116811253Sgdamore@opensolaris.org {
116911253Sgdamore@opensolaris.org 	const char	*link;
117011253Sgdamore@opensolaris.org 	int		num;
117111253Sgdamore@opensolaris.org 	int		fd;
117211253Sgdamore@opensolaris.org 	int		verbose = *(int *)arg;
117311253Sgdamore@opensolaris.org 	int		num_offset;
117411253Sgdamore@opensolaris.org 
117511253Sgdamore@opensolaris.org 	num_offset = sizeof ("/dev/mixer") - 1;
117611253Sgdamore@opensolaris.org 
117711253Sgdamore@opensolaris.org 	link = di_devlink_path(dlink);
117811253Sgdamore@opensolaris.org 
117911253Sgdamore@opensolaris.org 	if ((link == NULL) ||
118011253Sgdamore@opensolaris.org 	    (strncmp(link, "/dev/mixer", num_offset) != 0) ||
118111253Sgdamore@opensolaris.org 	    (!isdigit(link[num_offset]))) {
118211253Sgdamore@opensolaris.org 		return (DI_WALK_CONTINUE);
118311253Sgdamore@opensolaris.org 	}
118411253Sgdamore@opensolaris.org 
118511253Sgdamore@opensolaris.org 	num = atoi(link + num_offset);
118611253Sgdamore@opensolaris.org 	if ((fd = open(link, O_RDWR)) < 0) {
118711253Sgdamore@opensolaris.org 		if (verbose) {
118811253Sgdamore@opensolaris.org 			if (errno == ENOENT) {
118911253Sgdamore@opensolaris.org 				msg(_("Device %s not present.\n"), link);
119011253Sgdamore@opensolaris.org 			} else {
119111253Sgdamore@opensolaris.org 				msg(_("Unable to open device %s: %s\n"),
119211253Sgdamore@opensolaris.org 				    link, strerror(errno));
119311253Sgdamore@opensolaris.org 			}
119411253Sgdamore@opensolaris.org 		}
119511253Sgdamore@opensolaris.org 		return (DI_WALK_CONTINUE);
119611253Sgdamore@opensolaris.org 	}
119711253Sgdamore@opensolaris.org 
119811253Sgdamore@opensolaris.org 	if (verbose) {
119911253Sgdamore@opensolaris.org 		msg(_("Initializing link %s: "), link);
120011253Sgdamore@opensolaris.org 	}
120111253Sgdamore@opensolaris.org 	if (ioctl(fd, SNDCTL_SUN_SEND_NUMBER, &num) != 0) {
120211253Sgdamore@opensolaris.org 		if (verbose) {
120311253Sgdamore@opensolaris.org 			msg(_("failed: %s\n"), strerror(errno));
120411253Sgdamore@opensolaris.org 		}
120511253Sgdamore@opensolaris.org 	} else {
120611253Sgdamore@opensolaris.org 		if (verbose) {
120711253Sgdamore@opensolaris.org 			msg(_("done.\n"));
120811253Sgdamore@opensolaris.org 		}
120911253Sgdamore@opensolaris.org 	}
121011253Sgdamore@opensolaris.org 	(void) close(fd);
121111253Sgdamore@opensolaris.org 	return (DI_WALK_CONTINUE);
121211253Sgdamore@opensolaris.org }
121311253Sgdamore@opensolaris.org 
121411253Sgdamore@opensolaris.org int
do_init_devices(int argc,char ** argv)121511253Sgdamore@opensolaris.org do_init_devices(int argc, char **argv)
121611253Sgdamore@opensolaris.org {
121711253Sgdamore@opensolaris.org 	int			optc;
121811253Sgdamore@opensolaris.org 	di_devlink_handle_t	dlh;
121911253Sgdamore@opensolaris.org 	int			verbose = 0;
122011253Sgdamore@opensolaris.org 
122111253Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "v")) != EOF) {
122211253Sgdamore@opensolaris.org 		switch (optc) {
122311253Sgdamore@opensolaris.org 		case 'v':
122411253Sgdamore@opensolaris.org 			verbose = 1;
122511253Sgdamore@opensolaris.org 			break;
122611253Sgdamore@opensolaris.org 		default:
122711253Sgdamore@opensolaris.org 			help();
122811253Sgdamore@opensolaris.org 			return (-1);
122911253Sgdamore@opensolaris.org 		}
123011253Sgdamore@opensolaris.org 	}
123111253Sgdamore@opensolaris.org 	argc -= optind;
123211253Sgdamore@opensolaris.org 	argv += optind;
123311253Sgdamore@opensolaris.org 
123411253Sgdamore@opensolaris.org 	if (argc != 0) {
123511253Sgdamore@opensolaris.org 		help();
123611253Sgdamore@opensolaris.org 		return (-1);
123711253Sgdamore@opensolaris.org 	}
123811253Sgdamore@opensolaris.org 
123911253Sgdamore@opensolaris.org 	dlh = di_devlink_init(NULL, 0);
124011253Sgdamore@opensolaris.org 	if (dlh == NULL) {
124111253Sgdamore@opensolaris.org 		perror(_("Unable to initialize devlink handle"));
124211253Sgdamore@opensolaris.org 		return (-1);
124311253Sgdamore@opensolaris.org 	}
124411253Sgdamore@opensolaris.org 
124511253Sgdamore@opensolaris.org 	if (di_devlink_walk(dlh, "^mixer", NULL, 0, &verbose,
124611253Sgdamore@opensolaris.org 	    mixer_walker) != 0) {
124711253Sgdamore@opensolaris.org 		perror(_("Unable to walk devlinks"));
124811253Sgdamore@opensolaris.org 		return (-1);
124911253Sgdamore@opensolaris.org 	}
125011253Sgdamore@opensolaris.org 	return (0);
125111253Sgdamore@opensolaris.org }
125211253Sgdamore@opensolaris.org 
125311253Sgdamore@opensolaris.org int
main(int argc,char ** argv)125411230Sgdamore@opensolaris.org main(int argc, char **argv)
125511230Sgdamore@opensolaris.org {
125611230Sgdamore@opensolaris.org 	int rv = 0;
125711230Sgdamore@opensolaris.org 	int opt;
125811230Sgdamore@opensolaris.org 
125911230Sgdamore@opensolaris.org 	(void) setlocale(LC_ALL, "");
126011230Sgdamore@opensolaris.org 	(void) textdomain(TEXT_DOMAIN);
126111230Sgdamore@opensolaris.org 
126211230Sgdamore@opensolaris.org 	while ((opt = getopt(argc, argv, "h")) != EOF) {
126311230Sgdamore@opensolaris.org 		switch (opt) {
126411230Sgdamore@opensolaris.org 		case 'h':
126511230Sgdamore@opensolaris.org 			help();
126611230Sgdamore@opensolaris.org 			rv = 0;
126711230Sgdamore@opensolaris.org 			goto OUT;
126811230Sgdamore@opensolaris.org 		default:
126911230Sgdamore@opensolaris.org 			rv = EINVAL;
127011230Sgdamore@opensolaris.org 			break;
127111230Sgdamore@opensolaris.org 		}
127211230Sgdamore@opensolaris.org 	}
127311230Sgdamore@opensolaris.org 
127411230Sgdamore@opensolaris.org 	if (rv) {
127511230Sgdamore@opensolaris.org 		goto OUT;
127611230Sgdamore@opensolaris.org 	}
127711230Sgdamore@opensolaris.org 
127811230Sgdamore@opensolaris.org 	argc -= optind;
127911230Sgdamore@opensolaris.org 	argv += optind;
128011230Sgdamore@opensolaris.org 
128111230Sgdamore@opensolaris.org 	if (argc < 1) {
128211230Sgdamore@opensolaris.org 		help();
128311230Sgdamore@opensolaris.org 		rv = EINVAL;
128411230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "help") == 0) {
128511230Sgdamore@opensolaris.org 		help();
128611230Sgdamore@opensolaris.org 		rv = 0;
128711230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "list-devices") == 0) {
128811230Sgdamore@opensolaris.org 		rv = do_list_devices(argc, argv);
128911230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "show-device") == 0) {
129011230Sgdamore@opensolaris.org 		rv = do_show_device(argc, argv);
129111230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "show-control") == 0) {
129211230Sgdamore@opensolaris.org 		rv = do_show_control(argc, argv);
129311230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "set-control") == 0) {
129411230Sgdamore@opensolaris.org 		rv = do_set_control(argc, argv);
129511230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "load-controls") == 0) {
129611230Sgdamore@opensolaris.org 		rv = do_load_controls(argc, argv);
129711230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "save-controls") == 0) {
129811230Sgdamore@opensolaris.org 		rv = do_save_controls(argc, argv);
129911253Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "init-devices") == 0) {
130011253Sgdamore@opensolaris.org 		rv = do_init_devices(argc, argv);
130111230Sgdamore@opensolaris.org 	} else {
130211230Sgdamore@opensolaris.org 		help();
130311230Sgdamore@opensolaris.org 		rv = EINVAL;
130411230Sgdamore@opensolaris.org 	}
130511230Sgdamore@opensolaris.org 
130611230Sgdamore@opensolaris.org OUT:
130711230Sgdamore@opensolaris.org 	free_devices();
130811230Sgdamore@opensolaris.org 	return (rv);
130911230Sgdamore@opensolaris.org }
1310