1*11230Sgdamore@opensolaris.org /*
2*11230Sgdamore@opensolaris.org  * CDDL HEADER START
3*11230Sgdamore@opensolaris.org  *
4*11230Sgdamore@opensolaris.org  * The contents of this file are subject to the terms of the
5*11230Sgdamore@opensolaris.org  * Common Development and Distribution License (the "License").
6*11230Sgdamore@opensolaris.org  * You may not use this file except in compliance with the License.
7*11230Sgdamore@opensolaris.org  *
8*11230Sgdamore@opensolaris.org  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*11230Sgdamore@opensolaris.org  * or http://www.opensolaris.org/os/licensing.
10*11230Sgdamore@opensolaris.org  * See the License for the specific language governing permissions
11*11230Sgdamore@opensolaris.org  * and limitations under the License.
12*11230Sgdamore@opensolaris.org  *
13*11230Sgdamore@opensolaris.org  * When distributing Covered Code, include this CDDL HEADER in each
14*11230Sgdamore@opensolaris.org  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*11230Sgdamore@opensolaris.org  * If applicable, add the following below this CDDL HEADER, with the
16*11230Sgdamore@opensolaris.org  * fields enclosed by brackets "[]" replaced with your own identifying
17*11230Sgdamore@opensolaris.org  * information: Portions Copyright [yyyy] [name of copyright owner]
18*11230Sgdamore@opensolaris.org  *
19*11230Sgdamore@opensolaris.org  * CDDL HEADER END
20*11230Sgdamore@opensolaris.org  */
21*11230Sgdamore@opensolaris.org /*
22*11230Sgdamore@opensolaris.org  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*11230Sgdamore@opensolaris.org  * Use is subject to license terms.
24*11230Sgdamore@opensolaris.org  */
25*11230Sgdamore@opensolaris.org 
26*11230Sgdamore@opensolaris.org #include <stdio.h>
27*11230Sgdamore@opensolaris.org #include <stdlib.h>
28*11230Sgdamore@opensolaris.org #include <errno.h>
29*11230Sgdamore@opensolaris.org #include <string.h>
30*11230Sgdamore@opensolaris.org #include <strings.h>
31*11230Sgdamore@opensolaris.org #include <locale.h>
32*11230Sgdamore@opensolaris.org #include <libintl.h>
33*11230Sgdamore@opensolaris.org #include <stdarg.h>
34*11230Sgdamore@opensolaris.org #include <stddef.h>
35*11230Sgdamore@opensolaris.org #include <sys/types.h>
36*11230Sgdamore@opensolaris.org #include <sys/stat.h>
37*11230Sgdamore@opensolaris.org #include <sys/mkdev.h>
38*11230Sgdamore@opensolaris.org #include <fcntl.h>
39*11230Sgdamore@opensolaris.org #include <unistd.h>
40*11230Sgdamore@opensolaris.org #include <ctype.h>
41*11230Sgdamore@opensolaris.org #include <sys/param.h>
42*11230Sgdamore@opensolaris.org #include <sys/soundcard.h>
43*11230Sgdamore@opensolaris.org 
44*11230Sgdamore@opensolaris.org #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
45*11230Sgdamore@opensolaris.org #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
46*11230Sgdamore@opensolaris.org #endif
47*11230Sgdamore@opensolaris.org 
48*11230Sgdamore@opensolaris.org #define	_(s)	gettext(s)
49*11230Sgdamore@opensolaris.org 
50*11230Sgdamore@opensolaris.org #define	MAXLINE	1024
51*11230Sgdamore@opensolaris.org 
52*11230Sgdamore@opensolaris.org #define	AUDIO_CTRL_STEREO_LEFT(v)	((uint8_t)((v) & 0xff))
53*11230Sgdamore@opensolaris.org #define	AUDIO_CTRL_STEREO_RIGHT(v)	((uint8_t)(((v) >> 8) & 0xff))
54*11230Sgdamore@opensolaris.org #define	AUDIO_CTRL_STEREO_VAL(l, r)	(((l) & 0xff) | (((r) & 0xff) << 8))
55*11230Sgdamore@opensolaris.org 
56*11230Sgdamore@opensolaris.org /*
57*11230Sgdamore@opensolaris.org  * These are borrowed from sys/audio/audio_common.h, where the values
58*11230Sgdamore@opensolaris.org  * are protected by _KERNEL.
59*11230Sgdamore@opensolaris.org  */
60*11230Sgdamore@opensolaris.org #define	AUDIO_MN_TYPE_NBITS	(4)
61*11230Sgdamore@opensolaris.org #define	AUDIO_MN_TYPE_MASK	((1U << AUDIO_MN_TYPE_NBITS) - 1)
62*11230Sgdamore@opensolaris.org #define	AUDIO_MINOR_MIXER	(0)
63*11230Sgdamore@opensolaris.org 
64*11230Sgdamore@opensolaris.org 
65*11230Sgdamore@opensolaris.org /*
66*11230Sgdamore@opensolaris.org  * Column display information
67*11230Sgdamore@opensolaris.org  * All are related to the types enumerated in col_t and any change should be
68*11230Sgdamore@opensolaris.org  * reflected in the corresponding indices and offsets for all the variables
69*11230Sgdamore@opensolaris.org  * accordingly.  Most tweaks to the display can be done by adjusting the
70*11230Sgdamore@opensolaris.org  * values here.
71*11230Sgdamore@opensolaris.org  */
72*11230Sgdamore@opensolaris.org 
73*11230Sgdamore@opensolaris.org /* types of columns displayed */
74*11230Sgdamore@opensolaris.org typedef enum { COL_DV = 0, COL_NM, COL_VAL, COL_SEL} col_t;
75*11230Sgdamore@opensolaris.org 
76*11230Sgdamore@opensolaris.org /* corresponding sizes of columns; does not include trailing null */
77*11230Sgdamore@opensolaris.org #define	COL_DV_SZ	16
78*11230Sgdamore@opensolaris.org #define	COL_NM_SZ	24
79*11230Sgdamore@opensolaris.org #define	COL_VAL_SZ	10
80*11230Sgdamore@opensolaris.org #define	COL_SEL_SZ	20
81*11230Sgdamore@opensolaris.org #define	COL_MAX_SZ	64
82*11230Sgdamore@opensolaris.org 
83*11230Sgdamore@opensolaris.org /* corresponding sizes of columns, indexed by col_t value */
84*11230Sgdamore@opensolaris.org static int col_sz[] = {
85*11230Sgdamore@opensolaris.org 	COL_DV_SZ, COL_NM_SZ, COL_VAL_SZ, COL_SEL_SZ
86*11230Sgdamore@opensolaris.org };
87*11230Sgdamore@opensolaris.org 
88*11230Sgdamore@opensolaris.org /* used by callers of the printing function */
89*11230Sgdamore@opensolaris.org typedef struct col_prt {
90*11230Sgdamore@opensolaris.org 	char *col_dv;
91*11230Sgdamore@opensolaris.org 	char *col_nm;
92*11230Sgdamore@opensolaris.org 	char *col_val;
93*11230Sgdamore@opensolaris.org 	char *col_sel;
94*11230Sgdamore@opensolaris.org } col_prt_t;
95*11230Sgdamore@opensolaris.org 
96*11230Sgdamore@opensolaris.org /* columns displayed in order with vopt = 0 */
97*11230Sgdamore@opensolaris.org static int col_dpy[] = {COL_NM, COL_VAL};
98*11230Sgdamore@opensolaris.org static int col_dpy_len = sizeof (col_dpy) / sizeof (*col_dpy);
99*11230Sgdamore@opensolaris.org 
100*11230Sgdamore@opensolaris.org /* tells the printing function what members to use; follows col_dpy[] */
101*11230Sgdamore@opensolaris.org static size_t col_dpy_prt[] = {
102*11230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_nm),
103*11230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_val),
104*11230Sgdamore@opensolaris.org };
105*11230Sgdamore@opensolaris.org 
106*11230Sgdamore@opensolaris.org /* columns displayed in order with vopt = 1 */
107*11230Sgdamore@opensolaris.org static int col_dpy_vopt[] = { COL_DV, COL_NM, COL_VAL, COL_SEL};
108*11230Sgdamore@opensolaris.org static int col_dpy_vopt_len = sizeof (col_dpy_vopt) / sizeof (*col_dpy_vopt);
109*11230Sgdamore@opensolaris.org 
110*11230Sgdamore@opensolaris.org /* tells the printing function what members to use; follows col_dpy_vopt[] */
111*11230Sgdamore@opensolaris.org static size_t col_dpy_prt_vopt[] = {
112*11230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_dv),
113*11230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_nm),
114*11230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_val),
115*11230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_sel)
116*11230Sgdamore@opensolaris.org };
117*11230Sgdamore@opensolaris.org 
118*11230Sgdamore@opensolaris.org /* columns displayed in order with tofile = 1 */
119*11230Sgdamore@opensolaris.org static int col_dpy_tofile[] = { COL_NM, COL_VAL};
120*11230Sgdamore@opensolaris.org static int col_dpy_tofile_len = sizeof (col_dpy_tofile) /
121*11230Sgdamore@opensolaris.org     sizeof (*col_dpy_tofile);
122*11230Sgdamore@opensolaris.org 
123*11230Sgdamore@opensolaris.org /* tells the printing function what members to use; follows col_dpy_tofile[] */
124*11230Sgdamore@opensolaris.org static size_t col_dpy_prt_tofile[] = {
125*11230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_nm),
126*11230Sgdamore@opensolaris.org 	offsetof(col_prt_t, col_val)
127*11230Sgdamore@opensolaris.org };
128*11230Sgdamore@opensolaris.org 
129*11230Sgdamore@opensolaris.org 
130*11230Sgdamore@opensolaris.org /*
131*11230Sgdamore@opensolaris.org  * mixer and control accounting
132*11230Sgdamore@opensolaris.org  */
133*11230Sgdamore@opensolaris.org 
134*11230Sgdamore@opensolaris.org typedef struct cinfo {
135*11230Sgdamore@opensolaris.org 	oss_mixext ci;
136*11230Sgdamore@opensolaris.org 	oss_mixer_enuminfo *enump;
137*11230Sgdamore@opensolaris.org } cinfo_t;
138*11230Sgdamore@opensolaris.org 
139*11230Sgdamore@opensolaris.org typedef struct device {
140*11230Sgdamore@opensolaris.org 	oss_card_info	card;
141*11230Sgdamore@opensolaris.org 	oss_mixerinfo	mixer;
142*11230Sgdamore@opensolaris.org 
143*11230Sgdamore@opensolaris.org 	int		cmax;
144*11230Sgdamore@opensolaris.org 	cinfo_t		*controls;
145*11230Sgdamore@opensolaris.org 
146*11230Sgdamore@opensolaris.org 	int		mfd;
147*11230Sgdamore@opensolaris.org 	dev_t		devt;
148*11230Sgdamore@opensolaris.org 
149*11230Sgdamore@opensolaris.org 	struct device	*nextp;
150*11230Sgdamore@opensolaris.org } device_t;
151*11230Sgdamore@opensolaris.org 
152*11230Sgdamore@opensolaris.org static device_t	*devices = NULL;
153*11230Sgdamore@opensolaris.org 
154*11230Sgdamore@opensolaris.org /*PRINTFLIKE1*/
155*11230Sgdamore@opensolaris.org static void
156*11230Sgdamore@opensolaris.org msg(char *fmt, ...)
157*11230Sgdamore@opensolaris.org {
158*11230Sgdamore@opensolaris.org 	va_list ap;
159*11230Sgdamore@opensolaris.org 
160*11230Sgdamore@opensolaris.org 	va_start(ap, fmt);
161*11230Sgdamore@opensolaris.org 	(void) vprintf(fmt, ap);
162*11230Sgdamore@opensolaris.org 	va_end(ap);
163*11230Sgdamore@opensolaris.org }
164*11230Sgdamore@opensolaris.org 
165*11230Sgdamore@opensolaris.org /*PRINTFLIKE1*/
166*11230Sgdamore@opensolaris.org static void
167*11230Sgdamore@opensolaris.org warn(char *fmt, ...)
168*11230Sgdamore@opensolaris.org {
169*11230Sgdamore@opensolaris.org 	va_list ap;
170*11230Sgdamore@opensolaris.org 
171*11230Sgdamore@opensolaris.org 	va_start(ap, fmt);
172*11230Sgdamore@opensolaris.org 	(void) vfprintf(stderr, fmt, ap);
173*11230Sgdamore@opensolaris.org 	va_end(ap);
174*11230Sgdamore@opensolaris.org }
175*11230Sgdamore@opensolaris.org 
176*11230Sgdamore@opensolaris.org static void
177*11230Sgdamore@opensolaris.org free_device(device_t *d)
178*11230Sgdamore@opensolaris.org {
179*11230Sgdamore@opensolaris.org 	int		i;
180*11230Sgdamore@opensolaris.org 	device_t	**dpp;
181*11230Sgdamore@opensolaris.org 
182*11230Sgdamore@opensolaris.org 	dpp = &devices;
183*11230Sgdamore@opensolaris.org 	while ((*dpp) && ((*dpp) != d)) {
184*11230Sgdamore@opensolaris.org 		dpp = &((*dpp)->nextp);
185*11230Sgdamore@opensolaris.org 	}
186*11230Sgdamore@opensolaris.org 	if (*dpp) {
187*11230Sgdamore@opensolaris.org 		*dpp = d->nextp;
188*11230Sgdamore@opensolaris.org 	}
189*11230Sgdamore@opensolaris.org 	for (i = 0; i < d->cmax; i++) {
190*11230Sgdamore@opensolaris.org 		if (d->controls[i].enump != NULL)
191*11230Sgdamore@opensolaris.org 			free(d->controls[i].enump);
192*11230Sgdamore@opensolaris.org 	}
193*11230Sgdamore@opensolaris.org 
194*11230Sgdamore@opensolaris.org 	if (d->mfd >= 0)
195*11230Sgdamore@opensolaris.org 		(void) close(d->mfd);
196*11230Sgdamore@opensolaris.org 
197*11230Sgdamore@opensolaris.org 	free(d);
198*11230Sgdamore@opensolaris.org }
199*11230Sgdamore@opensolaris.org 
200*11230Sgdamore@opensolaris.org static void
201*11230Sgdamore@opensolaris.org free_devices(void)
202*11230Sgdamore@opensolaris.org {
203*11230Sgdamore@opensolaris.org 	device_t *d = devices;
204*11230Sgdamore@opensolaris.org 
205*11230Sgdamore@opensolaris.org 	while ((d = devices) != NULL) {
206*11230Sgdamore@opensolaris.org 		free_device(d);
207*11230Sgdamore@opensolaris.org 	}
208*11230Sgdamore@opensolaris.org 
209*11230Sgdamore@opensolaris.org 	devices = NULL;
210*11230Sgdamore@opensolaris.org }
211*11230Sgdamore@opensolaris.org 
212*11230Sgdamore@opensolaris.org 
213*11230Sgdamore@opensolaris.org /*
214*11230Sgdamore@opensolaris.org  * adds to the end of global devices and returns a pointer to the new entry
215*11230Sgdamore@opensolaris.org  */
216*11230Sgdamore@opensolaris.org static device_t *
217*11230Sgdamore@opensolaris.org alloc_device(void)
218*11230Sgdamore@opensolaris.org {
219*11230Sgdamore@opensolaris.org 	device_t *p;
220*11230Sgdamore@opensolaris.org 	device_t *d = calloc(1, sizeof (*d));
221*11230Sgdamore@opensolaris.org 
222*11230Sgdamore@opensolaris.org 	d->card.card = -1;
223*11230Sgdamore@opensolaris.org 	d->mixer.dev = -1;
224*11230Sgdamore@opensolaris.org 	d->mfd = -1;
225*11230Sgdamore@opensolaris.org 
226*11230Sgdamore@opensolaris.org 	if (devices == NULL) {
227*11230Sgdamore@opensolaris.org 		devices = d;
228*11230Sgdamore@opensolaris.org 	} else {
229*11230Sgdamore@opensolaris.org 		for (p = devices; p->nextp != NULL; p = p->nextp) {}
230*11230Sgdamore@opensolaris.org 
231*11230Sgdamore@opensolaris.org 		p->nextp = d;
232*11230Sgdamore@opensolaris.org 	}
233*11230Sgdamore@opensolaris.org 	return (d);
234*11230Sgdamore@opensolaris.org }
235*11230Sgdamore@opensolaris.org 
236*11230Sgdamore@opensolaris.org 
237*11230Sgdamore@opensolaris.org /*
238*11230Sgdamore@opensolaris.org  * cinfop->enump needs to be present
239*11230Sgdamore@opensolaris.org  * idx should be: >= 0 to < cinfop->ci.maxvalue
240*11230Sgdamore@opensolaris.org  */
241*11230Sgdamore@opensolaris.org static char *
242*11230Sgdamore@opensolaris.org get_enum_str(cinfo_t *cinfop, int idx)
243*11230Sgdamore@opensolaris.org {
244*11230Sgdamore@opensolaris.org 	int sz = sizeof (*cinfop->ci.enum_present) * 8;
245*11230Sgdamore@opensolaris.org 
246*11230Sgdamore@opensolaris.org 	if (cinfop->ci.enum_present[idx / sz] & (1 << (idx % sz)))
247*11230Sgdamore@opensolaris.org 		return (cinfop->enump->strings + cinfop->enump->strindex[idx]);
248*11230Sgdamore@opensolaris.org 
249*11230Sgdamore@opensolaris.org 	return (NULL);
250*11230Sgdamore@opensolaris.org }
251*11230Sgdamore@opensolaris.org 
252*11230Sgdamore@opensolaris.org 
253*11230Sgdamore@opensolaris.org /*
254*11230Sgdamore@opensolaris.org  * caller fills in d->mixer.devnode; func fills in the rest
255*11230Sgdamore@opensolaris.org  */
256*11230Sgdamore@opensolaris.org static int
257*11230Sgdamore@opensolaris.org get_device_info(device_t *d)
258*11230Sgdamore@opensolaris.org {
259*11230Sgdamore@opensolaris.org 	int fd = -1;
260*11230Sgdamore@opensolaris.org 	int i;
261*11230Sgdamore@opensolaris.org 	cinfo_t *ci;
262*11230Sgdamore@opensolaris.org 
263*11230Sgdamore@opensolaris.org 	if ((fd = open(d->mixer.devnode, O_RDWR)) < 0) {
264*11230Sgdamore@opensolaris.org 		perror(_("Error opening device"));
265*11230Sgdamore@opensolaris.org 		return (errno);
266*11230Sgdamore@opensolaris.org 	}
267*11230Sgdamore@opensolaris.org 	d->mfd = fd;
268*11230Sgdamore@opensolaris.org 
269*11230Sgdamore@opensolaris.org 	d->cmax = -1;
270*11230Sgdamore@opensolaris.org 	if (ioctl(fd, SNDCTL_MIX_NREXT, &d->cmax) < 0) {
271*11230Sgdamore@opensolaris.org 		perror(_("Error getting control count"));
272*11230Sgdamore@opensolaris.org 		return (errno);
273*11230Sgdamore@opensolaris.org 	}
274*11230Sgdamore@opensolaris.org 
275*11230Sgdamore@opensolaris.org 	d->controls = calloc(d->cmax, sizeof (*d->controls));
276*11230Sgdamore@opensolaris.org 
277*11230Sgdamore@opensolaris.org 	for (i = 0; i < d->cmax; i++) {
278*11230Sgdamore@opensolaris.org 		ci = &d->controls[i];
279*11230Sgdamore@opensolaris.org 
280*11230Sgdamore@opensolaris.org 		ci->ci.dev = -1;
281*11230Sgdamore@opensolaris.org 		ci->ci.ctrl = i;
282*11230Sgdamore@opensolaris.org 
283*11230Sgdamore@opensolaris.org 		if (ioctl(fd, SNDCTL_MIX_EXTINFO, &ci->ci) < 0) {
284*11230Sgdamore@opensolaris.org 			perror(_("Error getting control info"));
285*11230Sgdamore@opensolaris.org 			return (errno);
286*11230Sgdamore@opensolaris.org 		}
287*11230Sgdamore@opensolaris.org 
288*11230Sgdamore@opensolaris.org 		if (ci->ci.type == MIXT_ENUM) {
289*11230Sgdamore@opensolaris.org 			ci->enump = calloc(1, sizeof (*ci->enump));
290*11230Sgdamore@opensolaris.org 			ci->enump->dev = -1;
291*11230Sgdamore@opensolaris.org 			ci->enump->ctrl = ci->ci.ctrl;
292*11230Sgdamore@opensolaris.org 
293*11230Sgdamore@opensolaris.org 			if (ioctl(fd, SNDCTL_MIX_ENUMINFO, ci->enump) < 0) {
294*11230Sgdamore@opensolaris.org 				perror(_("Error getting enum info"));
295*11230Sgdamore@opensolaris.org 				return (errno);
296*11230Sgdamore@opensolaris.org 			}
297*11230Sgdamore@opensolaris.org 		}
298*11230Sgdamore@opensolaris.org 	}
299*11230Sgdamore@opensolaris.org 
300*11230Sgdamore@opensolaris.org 	return (0);
301*11230Sgdamore@opensolaris.org }
302*11230Sgdamore@opensolaris.org 
303*11230Sgdamore@opensolaris.org 
304*11230Sgdamore@opensolaris.org static int
305*11230Sgdamore@opensolaris.org load_devices(void)
306*11230Sgdamore@opensolaris.org {
307*11230Sgdamore@opensolaris.org 	int rv = -1;
308*11230Sgdamore@opensolaris.org 	int fd = -1;
309*11230Sgdamore@opensolaris.org 	int i;
310*11230Sgdamore@opensolaris.org 	oss_sysinfo si;
311*11230Sgdamore@opensolaris.org 	device_t *d;
312*11230Sgdamore@opensolaris.org 
313*11230Sgdamore@opensolaris.org 	if ((fd = open("/dev/mixer", O_RDWR)) < 0) {
314*11230Sgdamore@opensolaris.org 		rv = errno;
315*11230Sgdamore@opensolaris.org 		warn(_("Error opening mixer\n"));
316*11230Sgdamore@opensolaris.org 		goto OUT;
317*11230Sgdamore@opensolaris.org 	}
318*11230Sgdamore@opensolaris.org 
319*11230Sgdamore@opensolaris.org 	if (ioctl(fd, SNDCTL_SYSINFO, &si) < 0) {
320*11230Sgdamore@opensolaris.org 		rv = errno;
321*11230Sgdamore@opensolaris.org 		perror(_("Error getting system information"));
322*11230Sgdamore@opensolaris.org 		goto OUT;
323*11230Sgdamore@opensolaris.org 	}
324*11230Sgdamore@opensolaris.org 
325*11230Sgdamore@opensolaris.org 	for (i = 0; i < si.nummixers; i++) {
326*11230Sgdamore@opensolaris.org 
327*11230Sgdamore@opensolaris.org 		struct stat sbuf;
328*11230Sgdamore@opensolaris.org 
329*11230Sgdamore@opensolaris.org 		d = alloc_device();
330*11230Sgdamore@opensolaris.org 		d->mixer.dev = i;
331*11230Sgdamore@opensolaris.org 
332*11230Sgdamore@opensolaris.org 		if (ioctl(fd, SNDCTL_MIXERINFO, &d->mixer) != 0) {
333*11230Sgdamore@opensolaris.org 			continue;
334*11230Sgdamore@opensolaris.org 		}
335*11230Sgdamore@opensolaris.org 
336*11230Sgdamore@opensolaris.org 		d->card.card = d->mixer.card_number;
337*11230Sgdamore@opensolaris.org 
338*11230Sgdamore@opensolaris.org 		if ((ioctl(fd, SNDCTL_CARDINFO, &d->card) != 0) ||
339*11230Sgdamore@opensolaris.org 		    (stat(d->mixer.devnode, &sbuf) != 0) ||
340*11230Sgdamore@opensolaris.org 		    ((sbuf.st_mode & S_IFCHR) == 0)) {
341*11230Sgdamore@opensolaris.org 			warn(_("Device present: %s\n"), d->mixer.devnode);
342*11230Sgdamore@opensolaris.org 			free_device(d);
343*11230Sgdamore@opensolaris.org 			continue;
344*11230Sgdamore@opensolaris.org 		}
345*11230Sgdamore@opensolaris.org 		d->devt = makedev(major(sbuf.st_rdev),
346*11230Sgdamore@opensolaris.org 		    minor(sbuf.st_rdev) & ~(AUDIO_MN_TYPE_MASK));
347*11230Sgdamore@opensolaris.org 
348*11230Sgdamore@opensolaris.org 		if ((rv = get_device_info(d)) != 0) {
349*11230Sgdamore@opensolaris.org 			free_device(d);
350*11230Sgdamore@opensolaris.org 			goto OUT;
351*11230Sgdamore@opensolaris.org 		}
352*11230Sgdamore@opensolaris.org 	}
353*11230Sgdamore@opensolaris.org 
354*11230Sgdamore@opensolaris.org 	rv = 0;
355*11230Sgdamore@opensolaris.org 
356*11230Sgdamore@opensolaris.org OUT:
357*11230Sgdamore@opensolaris.org 	if (fd >= 0)
358*11230Sgdamore@opensolaris.org 		(void) close(fd);
359*11230Sgdamore@opensolaris.org 	return (rv);
360*11230Sgdamore@opensolaris.org }
361*11230Sgdamore@opensolaris.org 
362*11230Sgdamore@opensolaris.org 
363*11230Sgdamore@opensolaris.org static int
364*11230Sgdamore@opensolaris.org ctype_valid(int type)
365*11230Sgdamore@opensolaris.org {
366*11230Sgdamore@opensolaris.org 	switch (type) {
367*11230Sgdamore@opensolaris.org 	case MIXT_ONOFF:
368*11230Sgdamore@opensolaris.org 	case MIXT_ENUM:
369*11230Sgdamore@opensolaris.org 	case MIXT_MONOSLIDER:
370*11230Sgdamore@opensolaris.org 	case MIXT_STEREOSLIDER:
371*11230Sgdamore@opensolaris.org 		return (1);
372*11230Sgdamore@opensolaris.org 	default:
373*11230Sgdamore@opensolaris.org 		return (0);
374*11230Sgdamore@opensolaris.org 	}
375*11230Sgdamore@opensolaris.org }
376*11230Sgdamore@opensolaris.org 
377*11230Sgdamore@opensolaris.org 
378*11230Sgdamore@opensolaris.org static void
379*11230Sgdamore@opensolaris.org print_control_line(FILE *sfp, col_prt_t *colp, int vopt)
380*11230Sgdamore@opensolaris.org {
381*11230Sgdamore@opensolaris.org 	int i;
382*11230Sgdamore@opensolaris.org 	size_t *col_prtp;
383*11230Sgdamore@opensolaris.org 	int *col_dpyp;
384*11230Sgdamore@opensolaris.org 	int col_cnt;
385*11230Sgdamore@opensolaris.org 	int col_type;
386*11230Sgdamore@opensolaris.org 	int width;
387*11230Sgdamore@opensolaris.org 	char *colstr;
388*11230Sgdamore@opensolaris.org 	char cbuf[COL_MAX_SZ + 1];
389*11230Sgdamore@opensolaris.org 	char line[128];
390*11230Sgdamore@opensolaris.org 	char *colsep =  " ";
391*11230Sgdamore@opensolaris.org 
392*11230Sgdamore@opensolaris.org 	if (sfp != NULL) {
393*11230Sgdamore@opensolaris.org 		col_prtp = col_dpy_prt_tofile;
394*11230Sgdamore@opensolaris.org 		col_dpyp = col_dpy_tofile;
395*11230Sgdamore@opensolaris.org 		col_cnt = col_dpy_tofile_len;
396*11230Sgdamore@opensolaris.org 	} else if (vopt) {
397*11230Sgdamore@opensolaris.org 		col_prtp = col_dpy_prt_vopt;
398*11230Sgdamore@opensolaris.org 		col_dpyp = col_dpy_vopt;
399*11230Sgdamore@opensolaris.org 		col_cnt = col_dpy_vopt_len;
400*11230Sgdamore@opensolaris.org 	} else {
401*11230Sgdamore@opensolaris.org 		col_prtp = col_dpy_prt;
402*11230Sgdamore@opensolaris.org 		col_dpyp = col_dpy;
403*11230Sgdamore@opensolaris.org 		col_cnt = col_dpy_len;
404*11230Sgdamore@opensolaris.org 	}
405*11230Sgdamore@opensolaris.org 
406*11230Sgdamore@opensolaris.org 	line[0] = '\0';
407*11230Sgdamore@opensolaris.org 
408*11230Sgdamore@opensolaris.org 	for (i = 0; i < col_cnt; i++) {
409*11230Sgdamore@opensolaris.org 		col_type = col_dpyp[i];
410*11230Sgdamore@opensolaris.org 		width = col_sz[col_type];
411*11230Sgdamore@opensolaris.org 		colstr = *(char **)(((size_t)colp) + col_prtp[i]);
412*11230Sgdamore@opensolaris.org 
413*11230Sgdamore@opensolaris.org 		(void) snprintf(cbuf, sizeof (cbuf), "%- *s",
414*11230Sgdamore@opensolaris.org 		    width > 0 ? width : 1,
415*11230Sgdamore@opensolaris.org 		    (colstr == NULL) ? "" : colstr);
416*11230Sgdamore@opensolaris.org 
417*11230Sgdamore@opensolaris.org 		(void) strlcat(line, cbuf, sizeof (line));
418*11230Sgdamore@opensolaris.org 		if (i < col_cnt - 1)
419*11230Sgdamore@opensolaris.org 			(void) strlcat(line, colsep, sizeof (line));
420*11230Sgdamore@opensolaris.org 	}
421*11230Sgdamore@opensolaris.org 
422*11230Sgdamore@opensolaris.org 	(void) fprintf(sfp ? sfp : stdout, "%s\n", line);
423*11230Sgdamore@opensolaris.org }
424*11230Sgdamore@opensolaris.org 
425*11230Sgdamore@opensolaris.org 
426*11230Sgdamore@opensolaris.org static void
427*11230Sgdamore@opensolaris.org print_header(FILE *sfp, int vopt)
428*11230Sgdamore@opensolaris.org {
429*11230Sgdamore@opensolaris.org 	col_prt_t col;
430*11230Sgdamore@opensolaris.org 
431*11230Sgdamore@opensolaris.org 	if (sfp) {
432*11230Sgdamore@opensolaris.org 		col.col_nm = _("#CONTROL");
433*11230Sgdamore@opensolaris.org 		col.col_val = _("VALUE");
434*11230Sgdamore@opensolaris.org 	} else {
435*11230Sgdamore@opensolaris.org 		col.col_dv = _("DEVICE");
436*11230Sgdamore@opensolaris.org 		col.col_nm = _("CONTROL");
437*11230Sgdamore@opensolaris.org 		col.col_val = _("VALUE");
438*11230Sgdamore@opensolaris.org 		col.col_sel = _("POSSIBLE");
439*11230Sgdamore@opensolaris.org 	}
440*11230Sgdamore@opensolaris.org 	print_control_line(sfp, &col, vopt);
441*11230Sgdamore@opensolaris.org }
442*11230Sgdamore@opensolaris.org 
443*11230Sgdamore@opensolaris.org 
444*11230Sgdamore@opensolaris.org static int
445*11230Sgdamore@opensolaris.org print_control(FILE *sfp, device_t *d, cinfo_t *cinfop, int vopt)
446*11230Sgdamore@opensolaris.org {
447*11230Sgdamore@opensolaris.org 	int mfd = d->mfd;
448*11230Sgdamore@opensolaris.org 	char *devnm = d->card.shortname;
449*11230Sgdamore@opensolaris.org 	oss_mixer_value cval;
450*11230Sgdamore@opensolaris.org 	char *str;
451*11230Sgdamore@opensolaris.org 	int i;
452*11230Sgdamore@opensolaris.org 	int idx = -1;
453*11230Sgdamore@opensolaris.org 	int rv = -1;
454*11230Sgdamore@opensolaris.org 	char valbuf[COL_VAL_SZ + 1];
455*11230Sgdamore@opensolaris.org 	char selbuf[COL_SEL_SZ + 1];
456*11230Sgdamore@opensolaris.org 	col_prt_t col;
457*11230Sgdamore@opensolaris.org 
458*11230Sgdamore@opensolaris.org 	cval.dev = -1;
459*11230Sgdamore@opensolaris.org 	cval.ctrl = cinfop->ci.ctrl;
460*11230Sgdamore@opensolaris.org 
461*11230Sgdamore@opensolaris.org 	if (ctype_valid(cinfop->ci.type)) {
462*11230Sgdamore@opensolaris.org 		if (ioctl(mfd, SNDCTL_MIX_READ, &cval) < 0) {
463*11230Sgdamore@opensolaris.org 			rv = errno;
464*11230Sgdamore@opensolaris.org 			perror(_("Error reading control\n"));
465*11230Sgdamore@opensolaris.org 			return (rv);
466*11230Sgdamore@opensolaris.org 		}
467*11230Sgdamore@opensolaris.org 	} else {
468*11230Sgdamore@opensolaris.org 		return (0);
469*11230Sgdamore@opensolaris.org 	}
470*11230Sgdamore@opensolaris.org 
471*11230Sgdamore@opensolaris.org 	/*
472*11230Sgdamore@opensolaris.org 	 * convert the control value into a string
473*11230Sgdamore@opensolaris.org 	 */
474*11230Sgdamore@opensolaris.org 	switch (cinfop->ci.type) {
475*11230Sgdamore@opensolaris.org 	case MIXT_ONOFF:
476*11230Sgdamore@opensolaris.org 		(void) snprintf(valbuf, sizeof (valbuf), "%s",
477*11230Sgdamore@opensolaris.org 		    cval.value ? _("on") : _("off"));
478*11230Sgdamore@opensolaris.org 		break;
479*11230Sgdamore@opensolaris.org 
480*11230Sgdamore@opensolaris.org 	case MIXT_MONOSLIDER:
481*11230Sgdamore@opensolaris.org 		(void) snprintf(valbuf, sizeof (valbuf), "%d",
482*11230Sgdamore@opensolaris.org 		    cval.value & 0xff);
483*11230Sgdamore@opensolaris.org 		break;
484*11230Sgdamore@opensolaris.org 
485*11230Sgdamore@opensolaris.org 	case MIXT_STEREOSLIDER:
486*11230Sgdamore@opensolaris.org 		(void) snprintf(valbuf, sizeof (valbuf), "%d:%d",
487*11230Sgdamore@opensolaris.org 		    (int)AUDIO_CTRL_STEREO_LEFT(cval.value),
488*11230Sgdamore@opensolaris.org 		    (int)AUDIO_CTRL_STEREO_RIGHT(cval.value));
489*11230Sgdamore@opensolaris.org 		break;
490*11230Sgdamore@opensolaris.org 
491*11230Sgdamore@opensolaris.org 	case MIXT_ENUM:
492*11230Sgdamore@opensolaris.org 		str = get_enum_str(cinfop, cval.value);
493*11230Sgdamore@opensolaris.org 		if (str == NULL) {
494*11230Sgdamore@opensolaris.org 			warn(_("Bad enum index %d for control '%s'\n"),
495*11230Sgdamore@opensolaris.org 			    cval.value, cinfop->ci.extname);
496*11230Sgdamore@opensolaris.org 			return (EINVAL);
497*11230Sgdamore@opensolaris.org 		}
498*11230Sgdamore@opensolaris.org 
499*11230Sgdamore@opensolaris.org 		(void) snprintf(valbuf, sizeof (valbuf), "%s", str);
500*11230Sgdamore@opensolaris.org 		break;
501*11230Sgdamore@opensolaris.org 
502*11230Sgdamore@opensolaris.org 	default:
503*11230Sgdamore@opensolaris.org 		return (0);
504*11230Sgdamore@opensolaris.org 	}
505*11230Sgdamore@opensolaris.org 
506*11230Sgdamore@opensolaris.org 	/*
507*11230Sgdamore@opensolaris.org 	 * possible control values (range/selection)
508*11230Sgdamore@opensolaris.org 	 */
509*11230Sgdamore@opensolaris.org 	switch (cinfop->ci.type) {
510*11230Sgdamore@opensolaris.org 	case MIXT_ONOFF:
511*11230Sgdamore@opensolaris.org 		(void) snprintf(selbuf, sizeof (selbuf), _("on,off"));
512*11230Sgdamore@opensolaris.org 		break;
513*11230Sgdamore@opensolaris.org 
514*11230Sgdamore@opensolaris.org 	case MIXT_MONOSLIDER:
515*11230Sgdamore@opensolaris.org 		(void) snprintf(selbuf, sizeof (selbuf), "%d-%d",
516*11230Sgdamore@opensolaris.org 		    cinfop->ci.minvalue, cinfop->ci.maxvalue);
517*11230Sgdamore@opensolaris.org 		break;
518*11230Sgdamore@opensolaris.org 	case MIXT_STEREOSLIDER:
519*11230Sgdamore@opensolaris.org 		(void) snprintf(selbuf, sizeof (selbuf), "%d-%d:%d-%d",
520*11230Sgdamore@opensolaris.org 		    cinfop->ci.minvalue, cinfop->ci.maxvalue,
521*11230Sgdamore@opensolaris.org 		    cinfop->ci.minvalue, cinfop->ci.maxvalue);
522*11230Sgdamore@opensolaris.org 		break;
523*11230Sgdamore@opensolaris.org 
524*11230Sgdamore@opensolaris.org 	case MIXT_ENUM:
525*11230Sgdamore@opensolaris.org 		/*
526*11230Sgdamore@opensolaris.org 		 * display the first choice on the same line, then display
527*11230Sgdamore@opensolaris.org 		 * the rest on multiple lines
528*11230Sgdamore@opensolaris.org 		 */
529*11230Sgdamore@opensolaris.org 		selbuf[0] = 0;
530*11230Sgdamore@opensolaris.org 		for (i = 0; i < cinfop->ci.maxvalue; i++) {
531*11230Sgdamore@opensolaris.org 			str = get_enum_str(cinfop, i);
532*11230Sgdamore@opensolaris.org 			if (str == NULL)
533*11230Sgdamore@opensolaris.org 				continue;
534*11230Sgdamore@opensolaris.org 
535*11230Sgdamore@opensolaris.org 			if ((strlen(str) + 1 + strlen(selbuf)) >=
536*11230Sgdamore@opensolaris.org 			    sizeof (selbuf)) {
537*11230Sgdamore@opensolaris.org 				break;
538*11230Sgdamore@opensolaris.org 			}
539*11230Sgdamore@opensolaris.org 			if (strlen(selbuf)) {
540*11230Sgdamore@opensolaris.org 				(void) strlcat(selbuf, ",", sizeof (selbuf));
541*11230Sgdamore@opensolaris.org 			}
542*11230Sgdamore@opensolaris.org 
543*11230Sgdamore@opensolaris.org 			(void) strlcat(selbuf, str, sizeof (selbuf));
544*11230Sgdamore@opensolaris.org 		}
545*11230Sgdamore@opensolaris.org 		idx = i;
546*11230Sgdamore@opensolaris.org 		break;
547*11230Sgdamore@opensolaris.org 
548*11230Sgdamore@opensolaris.org 	default:
549*11230Sgdamore@opensolaris.org 		(void) snprintf(selbuf, sizeof (selbuf), "-");
550*11230Sgdamore@opensolaris.org 	}
551*11230Sgdamore@opensolaris.org 
552*11230Sgdamore@opensolaris.org 	col.col_dv = devnm;
553*11230Sgdamore@opensolaris.org 	col.col_nm = strlen(cinfop->ci.extname) ?
554*11230Sgdamore@opensolaris.org 	    cinfop->ci.extname : cinfop->ci.id;
555*11230Sgdamore@opensolaris.org 	while (strchr(col.col_nm, '_') != NULL) {
556*11230Sgdamore@opensolaris.org 		col.col_nm = strchr(col.col_nm, '_') + 1;
557*11230Sgdamore@opensolaris.org 	}
558*11230Sgdamore@opensolaris.org 	col.col_val = valbuf;
559*11230Sgdamore@opensolaris.org 	col.col_sel = selbuf;
560*11230Sgdamore@opensolaris.org 	print_control_line(sfp, &col, vopt);
561*11230Sgdamore@opensolaris.org 
562*11230Sgdamore@opensolaris.org 	/* print leftover enum value selections */
563*11230Sgdamore@opensolaris.org 	while ((sfp == NULL) && (idx >= 0) && (idx < cinfop->ci.maxvalue)) {
564*11230Sgdamore@opensolaris.org 		selbuf[0] = 0;
565*11230Sgdamore@opensolaris.org 		for (i = idx; i < cinfop->ci.maxvalue; i++) {
566*11230Sgdamore@opensolaris.org 			str = get_enum_str(cinfop, i);
567*11230Sgdamore@opensolaris.org 			if (str == NULL)
568*11230Sgdamore@opensolaris.org 				continue;
569*11230Sgdamore@opensolaris.org 
570*11230Sgdamore@opensolaris.org 			if ((strlen(str) + 1 + strlen(selbuf)) >=
571*11230Sgdamore@opensolaris.org 			    sizeof (selbuf)) {
572*11230Sgdamore@opensolaris.org 				break;
573*11230Sgdamore@opensolaris.org 			}
574*11230Sgdamore@opensolaris.org 			if (strlen(selbuf)) {
575*11230Sgdamore@opensolaris.org 				(void) strlcat(selbuf, ",", sizeof (selbuf));
576*11230Sgdamore@opensolaris.org 			}
577*11230Sgdamore@opensolaris.org 
578*11230Sgdamore@opensolaris.org 			(void) strlcat(selbuf, str, sizeof (selbuf));
579*11230Sgdamore@opensolaris.org 		}
580*11230Sgdamore@opensolaris.org 		idx = i;
581*11230Sgdamore@opensolaris.org 		col.col_dv = NULL;
582*11230Sgdamore@opensolaris.org 		col.col_nm = NULL;
583*11230Sgdamore@opensolaris.org 		col.col_val = NULL;
584*11230Sgdamore@opensolaris.org 		col.col_sel = selbuf;
585*11230Sgdamore@opensolaris.org 		print_control_line(sfp, &col, vopt);
586*11230Sgdamore@opensolaris.org 	}
587*11230Sgdamore@opensolaris.org 
588*11230Sgdamore@opensolaris.org 	return (0);
589*11230Sgdamore@opensolaris.org }
590*11230Sgdamore@opensolaris.org 
591*11230Sgdamore@opensolaris.org 
592*11230Sgdamore@opensolaris.org static int
593*11230Sgdamore@opensolaris.org set_device_control(device_t *d, cinfo_t *cinfop, char *wstr, int vopt)
594*11230Sgdamore@opensolaris.org {
595*11230Sgdamore@opensolaris.org 	int mfd = d->mfd;
596*11230Sgdamore@opensolaris.org 	oss_mixer_value cval;
597*11230Sgdamore@opensolaris.org 	int wlen = strlen(wstr);
598*11230Sgdamore@opensolaris.org 	int lval, rval;
599*11230Sgdamore@opensolaris.org 	char *lstr, *rstr;
600*11230Sgdamore@opensolaris.org 	char *str;
601*11230Sgdamore@opensolaris.org 	int i;
602*11230Sgdamore@opensolaris.org 	int rv = -1;
603*11230Sgdamore@opensolaris.org 
604*11230Sgdamore@opensolaris.org 	cval.dev = -1;
605*11230Sgdamore@opensolaris.org 	cval.ctrl = cinfop->ci.ctrl;
606*11230Sgdamore@opensolaris.org 	cval.value = 0;
607*11230Sgdamore@opensolaris.org 
608*11230Sgdamore@opensolaris.org 	switch (cinfop->ci.type) {
609*11230Sgdamore@opensolaris.org 	case MIXT_ONOFF:
610*11230Sgdamore@opensolaris.org 		cval.value = (strncmp(_("on"), wstr, wlen) == 0) ? 1 : 0;
611*11230Sgdamore@opensolaris.org 		break;
612*11230Sgdamore@opensolaris.org 
613*11230Sgdamore@opensolaris.org 	case MIXT_MONOSLIDER:
614*11230Sgdamore@opensolaris.org 		cval.value = atoi(wstr);
615*11230Sgdamore@opensolaris.org 		break;
616*11230Sgdamore@opensolaris.org 
617*11230Sgdamore@opensolaris.org 	case MIXT_STEREOSLIDER:
618*11230Sgdamore@opensolaris.org 		lstr = wstr;
619*11230Sgdamore@opensolaris.org 		rstr = strchr(wstr, ':');
620*11230Sgdamore@opensolaris.org 		if (rstr != NULL) {
621*11230Sgdamore@opensolaris.org 			*rstr = '\0';
622*11230Sgdamore@opensolaris.org 			rstr++;
623*11230Sgdamore@opensolaris.org 
624*11230Sgdamore@opensolaris.org 			rval = atoi(rstr);
625*11230Sgdamore@opensolaris.org 			lval = atoi(lstr);
626*11230Sgdamore@opensolaris.org 
627*11230Sgdamore@opensolaris.org 			rstr--;
628*11230Sgdamore@opensolaris.org 			*rstr = ':';
629*11230Sgdamore@opensolaris.org 		} else {
630*11230Sgdamore@opensolaris.org 			lval = atoi(lstr);
631*11230Sgdamore@opensolaris.org 			rval = lval;
632*11230Sgdamore@opensolaris.org 		}
633*11230Sgdamore@opensolaris.org 
634*11230Sgdamore@opensolaris.org 		cval.value = AUDIO_CTRL_STEREO_VAL(lval, rval);
635*11230Sgdamore@opensolaris.org 		break;
636*11230Sgdamore@opensolaris.org 
637*11230Sgdamore@opensolaris.org 	case MIXT_ENUM:
638*11230Sgdamore@opensolaris.org 		for (i = 0; i < cinfop->ci.maxvalue; i++) {
639*11230Sgdamore@opensolaris.org 			str = get_enum_str(cinfop, i);
640*11230Sgdamore@opensolaris.org 			if (str == NULL)
641*11230Sgdamore@opensolaris.org 				continue;
642*11230Sgdamore@opensolaris.org 
643*11230Sgdamore@opensolaris.org 			if (strncmp(wstr, str, wlen) == 0) {
644*11230Sgdamore@opensolaris.org 				cval.value = i;
645*11230Sgdamore@opensolaris.org 				break;
646*11230Sgdamore@opensolaris.org 			}
647*11230Sgdamore@opensolaris.org 		}
648*11230Sgdamore@opensolaris.org 
649*11230Sgdamore@opensolaris.org 		if (i >= cinfop->ci.maxvalue) {
650*11230Sgdamore@opensolaris.org 			warn(_("Invalid enumeration value\n"));
651*11230Sgdamore@opensolaris.org 			return (EINVAL);
652*11230Sgdamore@opensolaris.org 		}
653*11230Sgdamore@opensolaris.org 		break;
654*11230Sgdamore@opensolaris.org 
655*11230Sgdamore@opensolaris.org 	default:
656*11230Sgdamore@opensolaris.org 		warn(_("Unsupported control type: %d\n"), cinfop->ci.type);
657*11230Sgdamore@opensolaris.org 		return (EINVAL);
658*11230Sgdamore@opensolaris.org 	}
659*11230Sgdamore@opensolaris.org 
660*11230Sgdamore@opensolaris.org 	if (vopt) {
661*11230Sgdamore@opensolaris.org 		msg(_("%s: '%s' set to '%s'\n"), d->card.shortname,
662*11230Sgdamore@opensolaris.org 		    cinfop->ci.extname, wstr);
663*11230Sgdamore@opensolaris.org 	}
664*11230Sgdamore@opensolaris.org 
665*11230Sgdamore@opensolaris.org 	if (ioctl(mfd, SNDCTL_MIX_WRITE, &cval) < 0) {
666*11230Sgdamore@opensolaris.org 		rv = errno;
667*11230Sgdamore@opensolaris.org 		perror(_("Error writing control"));
668*11230Sgdamore@opensolaris.org 		return (rv);
669*11230Sgdamore@opensolaris.org 	}
670*11230Sgdamore@opensolaris.org 
671*11230Sgdamore@opensolaris.org 	rv = 0;
672*11230Sgdamore@opensolaris.org 	return (rv);
673*11230Sgdamore@opensolaris.org }
674*11230Sgdamore@opensolaris.org 
675*11230Sgdamore@opensolaris.org 
676*11230Sgdamore@opensolaris.org static void
677*11230Sgdamore@opensolaris.org help(void)
678*11230Sgdamore@opensolaris.org {
679*11230Sgdamore@opensolaris.org #define	HELP_STR	_(						\
680*11230Sgdamore@opensolaris.org "audioctl list-devices\n"						\
681*11230Sgdamore@opensolaris.org "	list all audio devices\n"					\
682*11230Sgdamore@opensolaris.org "\n"									\
683*11230Sgdamore@opensolaris.org "audioctl show-device [ -v ] [ -d <device> ]\n"				\
684*11230Sgdamore@opensolaris.org "	display information about an audio device\n"			\
685*11230Sgdamore@opensolaris.org "\n"									\
686*11230Sgdamore@opensolaris.org "audioctl show-control [ -v ] [ -d <device> ] [ <control> ... ]\n"	\
687*11230Sgdamore@opensolaris.org "	get the value of a specific control (all if not specified)\n"	\
688*11230Sgdamore@opensolaris.org "\n"									\
689*11230Sgdamore@opensolaris.org "audioctl set-control [ -v ] [ -d <device> ] <control> <value>\n"	\
690*11230Sgdamore@opensolaris.org "	set the value of a specific control\n"				\
691*11230Sgdamore@opensolaris.org "\n"									\
692*11230Sgdamore@opensolaris.org "audioctl save-controls [ -d <device> ] [ -f ] <file>\n"		\
693*11230Sgdamore@opensolaris.org "	save all control settings for the device to a file\n"		\
694*11230Sgdamore@opensolaris.org "\n"									\
695*11230Sgdamore@opensolaris.org "audioctl load-controls [ -d <device> ] <file>\n"			\
696*11230Sgdamore@opensolaris.org "	restore previously saved control settings to device\n"		\
697*11230Sgdamore@opensolaris.org "\n"									\
698*11230Sgdamore@opensolaris.org "audioctl help\n"							\
699*11230Sgdamore@opensolaris.org "	show this message.\n")
700*11230Sgdamore@opensolaris.org 
701*11230Sgdamore@opensolaris.org 	(void) fprintf(stderr, HELP_STR);
702*11230Sgdamore@opensolaris.org }
703*11230Sgdamore@opensolaris.org 
704*11230Sgdamore@opensolaris.org dev_t
705*11230Sgdamore@opensolaris.org device_devt(char *name)
706*11230Sgdamore@opensolaris.org {
707*11230Sgdamore@opensolaris.org 	struct stat	sbuf;
708*11230Sgdamore@opensolaris.org 
709*11230Sgdamore@opensolaris.org 	if ((stat(name, &sbuf) != 0) ||
710*11230Sgdamore@opensolaris.org 	    ((sbuf.st_mode & S_IFCHR) == 0)) {
711*11230Sgdamore@opensolaris.org 		/* Not a device node! */
712*11230Sgdamore@opensolaris.org 		return (0);
713*11230Sgdamore@opensolaris.org 	}
714*11230Sgdamore@opensolaris.org 
715*11230Sgdamore@opensolaris.org 	return (makedev(major(sbuf.st_rdev),
716*11230Sgdamore@opensolaris.org 	    minor(sbuf.st_rdev) & ~(AUDIO_MN_TYPE_MASK)));
717*11230Sgdamore@opensolaris.org }
718*11230Sgdamore@opensolaris.org 
719*11230Sgdamore@opensolaris.org static device_t *
720*11230Sgdamore@opensolaris.org find_device(char *name)
721*11230Sgdamore@opensolaris.org {
722*11230Sgdamore@opensolaris.org 	dev_t		devt;
723*11230Sgdamore@opensolaris.org 	device_t	*d;
724*11230Sgdamore@opensolaris.org 
725*11230Sgdamore@opensolaris.org 	/*
726*11230Sgdamore@opensolaris.org 	 * User may have specified:
727*11230Sgdamore@opensolaris.org 	 *
728*11230Sgdamore@opensolaris.org 	 * /dev/dsp[<num>]
729*11230Sgdamore@opensolaris.org 	 * /dev/mixer[<num>]
730*11230Sgdamore@opensolaris.org 	 * /dev/audio[<num>9]
731*11230Sgdamore@opensolaris.org 	 * /dev/audioctl[<num>]
732*11230Sgdamore@opensolaris.org 	 * /dev/sound/<num>{,ctl,dsp,mixer}
733*11230Sgdamore@opensolaris.org 	 * /dev/sound/<driver>:<num>{,ctl,dsp,mixer}
734*11230Sgdamore@opensolaris.org 	 *
735*11230Sgdamore@opensolaris.org 	 * We can canonicalize these by looking at the dev_t though.
736*11230Sgdamore@opensolaris.org 	 */
737*11230Sgdamore@opensolaris.org 
738*11230Sgdamore@opensolaris.org 	if (name == NULL)
739*11230Sgdamore@opensolaris.org 		name = getenv("AUDIODEV");
740*11230Sgdamore@opensolaris.org 
741*11230Sgdamore@opensolaris.org 	if ((name == NULL) ||
742*11230Sgdamore@opensolaris.org 	    (strcmp(name, "/dev/mixer") == 0)) {
743*11230Sgdamore@opensolaris.org 		/* /dev/mixer node doesn't point to real hw */
744*11230Sgdamore@opensolaris.org 		name = "/dev/dsp";
745*11230Sgdamore@opensolaris.org 	}
746*11230Sgdamore@opensolaris.org 
747*11230Sgdamore@opensolaris.org 	if (*name == '/') {
748*11230Sgdamore@opensolaris.org 		/* if we have a full path, convert to the devt */
749*11230Sgdamore@opensolaris.org 		if ((devt = device_devt(name)) == 0) {
750*11230Sgdamore@opensolaris.org 			warn(_("No such audio device.\n"));
751*11230Sgdamore@opensolaris.org 			return (NULL);
752*11230Sgdamore@opensolaris.org 		}
753*11230Sgdamore@opensolaris.org 		name = NULL;
754*11230Sgdamore@opensolaris.org 	}
755*11230Sgdamore@opensolaris.org 
756*11230Sgdamore@opensolaris.org 	for (d = devices; d != NULL; d = d->nextp) {
757*11230Sgdamore@opensolaris.org 		oss_card_info *card = &d->card;
758*11230Sgdamore@opensolaris.org 
759*11230Sgdamore@opensolaris.org 		if ((name) && (strcmp(name, card->shortname) == 0)) {
760*11230Sgdamore@opensolaris.org 			return (d);
761*11230Sgdamore@opensolaris.org 		}
762*11230Sgdamore@opensolaris.org 		if (devt == d->devt) {
763*11230Sgdamore@opensolaris.org 			return (d);
764*11230Sgdamore@opensolaris.org 		}
765*11230Sgdamore@opensolaris.org 	}
766*11230Sgdamore@opensolaris.org 
767*11230Sgdamore@opensolaris.org 	warn(_("No such audio device.\n"));
768*11230Sgdamore@opensolaris.org 	return (NULL);
769*11230Sgdamore@opensolaris.org }
770*11230Sgdamore@opensolaris.org 
771*11230Sgdamore@opensolaris.org int
772*11230Sgdamore@opensolaris.org do_list_devices(int argc, char **argv)
773*11230Sgdamore@opensolaris.org {
774*11230Sgdamore@opensolaris.org 	int		optc;
775*11230Sgdamore@opensolaris.org 	int		verbose = 0;
776*11230Sgdamore@opensolaris.org 	device_t	*d;
777*11230Sgdamore@opensolaris.org 
778*11230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "v")) != EOF) {
779*11230Sgdamore@opensolaris.org 		switch (optc) {
780*11230Sgdamore@opensolaris.org 		case 'v':
781*11230Sgdamore@opensolaris.org 			verbose++;
782*11230Sgdamore@opensolaris.org 			break;
783*11230Sgdamore@opensolaris.org 		default:
784*11230Sgdamore@opensolaris.org 			help();
785*11230Sgdamore@opensolaris.org 			return (-1);
786*11230Sgdamore@opensolaris.org 		}
787*11230Sgdamore@opensolaris.org 	}
788*11230Sgdamore@opensolaris.org 	argc -= optind;
789*11230Sgdamore@opensolaris.org 	argv += optind;
790*11230Sgdamore@opensolaris.org 	if (argc != 0) {
791*11230Sgdamore@opensolaris.org 		help();
792*11230Sgdamore@opensolaris.org 		return (-1);
793*11230Sgdamore@opensolaris.org 	}
794*11230Sgdamore@opensolaris.org 
795*11230Sgdamore@opensolaris.org 	for (d = devices; d != NULL; d = d->nextp) {
796*11230Sgdamore@opensolaris.org 
797*11230Sgdamore@opensolaris.org 		if ((d->mixer.enabled == 0) && (!verbose))
798*11230Sgdamore@opensolaris.org 			continue;
799*11230Sgdamore@opensolaris.org 
800*11230Sgdamore@opensolaris.org 		if (verbose) {
801*11230Sgdamore@opensolaris.org 			msg(_("%s (%s)\n"), d->card.shortname,
802*11230Sgdamore@opensolaris.org 			    d->mixer.devnode);
803*11230Sgdamore@opensolaris.org 		} else {
804*11230Sgdamore@opensolaris.org 			msg(_("%s\n"), d->card.shortname);
805*11230Sgdamore@opensolaris.org 		}
806*11230Sgdamore@opensolaris.org 	}
807*11230Sgdamore@opensolaris.org 
808*11230Sgdamore@opensolaris.org 	return (0);
809*11230Sgdamore@opensolaris.org }
810*11230Sgdamore@opensolaris.org 
811*11230Sgdamore@opensolaris.org int
812*11230Sgdamore@opensolaris.org do_show_device(int argc, char **argv)
813*11230Sgdamore@opensolaris.org {
814*11230Sgdamore@opensolaris.org 	int		optc;
815*11230Sgdamore@opensolaris.org 	char		*devname = NULL;
816*11230Sgdamore@opensolaris.org 	device_t	*d;
817*11230Sgdamore@opensolaris.org 
818*11230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:v")) != EOF) {
819*11230Sgdamore@opensolaris.org 		switch (optc) {
820*11230Sgdamore@opensolaris.org 		case 'd':
821*11230Sgdamore@opensolaris.org 			devname = optarg;
822*11230Sgdamore@opensolaris.org 			break;
823*11230Sgdamore@opensolaris.org 		case 'v':
824*11230Sgdamore@opensolaris.org 			break;
825*11230Sgdamore@opensolaris.org 		default:
826*11230Sgdamore@opensolaris.org 			help();
827*11230Sgdamore@opensolaris.org 			return (-1);
828*11230Sgdamore@opensolaris.org 		}
829*11230Sgdamore@opensolaris.org 	}
830*11230Sgdamore@opensolaris.org 	argc -= optind;
831*11230Sgdamore@opensolaris.org 	argv += optind;
832*11230Sgdamore@opensolaris.org 	if (argc != 0) {
833*11230Sgdamore@opensolaris.org 		help();
834*11230Sgdamore@opensolaris.org 		return (-1);
835*11230Sgdamore@opensolaris.org 	}
836*11230Sgdamore@opensolaris.org 
837*11230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
838*11230Sgdamore@opensolaris.org 		return (ENODEV);
839*11230Sgdamore@opensolaris.org 	}
840*11230Sgdamore@opensolaris.org 
841*11230Sgdamore@opensolaris.org 	msg(_("Device: %s\n"), d->mixer.devnode);
842*11230Sgdamore@opensolaris.org 	msg(_("  Name    = %s\n"), d->card.shortname);
843*11230Sgdamore@opensolaris.org 	msg(_("  Config  = %s\n"), d->card.longname);
844*11230Sgdamore@opensolaris.org 
845*11230Sgdamore@opensolaris.org 	if (strlen(d->card.hw_info)) {
846*11230Sgdamore@opensolaris.org 		msg(_("  HW Info = %s"), d->card.hw_info);
847*11230Sgdamore@opensolaris.org 	}
848*11230Sgdamore@opensolaris.org 
849*11230Sgdamore@opensolaris.org 	return (0);
850*11230Sgdamore@opensolaris.org }
851*11230Sgdamore@opensolaris.org 
852*11230Sgdamore@opensolaris.org int
853*11230Sgdamore@opensolaris.org do_show_control(int argc, char **argv)
854*11230Sgdamore@opensolaris.org {
855*11230Sgdamore@opensolaris.org 	int		optc;
856*11230Sgdamore@opensolaris.org 	int		rval = 0;
857*11230Sgdamore@opensolaris.org 	int		verbose = 0;
858*11230Sgdamore@opensolaris.org 	device_t	*d;
859*11230Sgdamore@opensolaris.org 	char		*devname = NULL;
860*11230Sgdamore@opensolaris.org 	int		i;
861*11230Sgdamore@opensolaris.org 	int		j;
862*11230Sgdamore@opensolaris.org 	int		rv;
863*11230Sgdamore@opensolaris.org 	char		*n;
864*11230Sgdamore@opensolaris.org 	cinfo_t		*cinfop;
865*11230Sgdamore@opensolaris.org 
866*11230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:v")) != EOF) {
867*11230Sgdamore@opensolaris.org 		switch (optc) {
868*11230Sgdamore@opensolaris.org 		case 'd':
869*11230Sgdamore@opensolaris.org 			devname = optarg;
870*11230Sgdamore@opensolaris.org 			break;
871*11230Sgdamore@opensolaris.org 		case 'v':
872*11230Sgdamore@opensolaris.org 			verbose++;
873*11230Sgdamore@opensolaris.org 			break;
874*11230Sgdamore@opensolaris.org 		default:
875*11230Sgdamore@opensolaris.org 			help();
876*11230Sgdamore@opensolaris.org 			return (-1);
877*11230Sgdamore@opensolaris.org 		}
878*11230Sgdamore@opensolaris.org 	}
879*11230Sgdamore@opensolaris.org 	argc -= optind;
880*11230Sgdamore@opensolaris.org 	argv += optind;
881*11230Sgdamore@opensolaris.org 
882*11230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
883*11230Sgdamore@opensolaris.org 		return (ENODEV);
884*11230Sgdamore@opensolaris.org 	}
885*11230Sgdamore@opensolaris.org 
886*11230Sgdamore@opensolaris.org 	print_header(NULL, verbose);
887*11230Sgdamore@opensolaris.org 	if (argc == 0) {
888*11230Sgdamore@opensolaris.org 		/* do them all! */
889*11230Sgdamore@opensolaris.org 		for (i = 0; i < d->cmax; i++) {
890*11230Sgdamore@opensolaris.org 
891*11230Sgdamore@opensolaris.org 			cinfop = &d->controls[i];
892*11230Sgdamore@opensolaris.org 			rv = print_control(NULL, d, cinfop, verbose);
893*11230Sgdamore@opensolaris.org 			rval = rval ? rval : rv;
894*11230Sgdamore@opensolaris.org 		}
895*11230Sgdamore@opensolaris.org 		return (rval);
896*11230Sgdamore@opensolaris.org 	}
897*11230Sgdamore@opensolaris.org 
898*11230Sgdamore@opensolaris.org 	for (i = 0; i < argc; i++) {
899*11230Sgdamore@opensolaris.org 		for (j = 0; j < d->cmax; j++) {
900*11230Sgdamore@opensolaris.org 			cinfop = &d->controls[j];
901*11230Sgdamore@opensolaris.org 			n = strrchr(cinfop->ci.extname, '_');
902*11230Sgdamore@opensolaris.org 			n = n ? n + 1 : cinfop->ci.extname;
903*11230Sgdamore@opensolaris.org 			if (strcmp(argv[i], n) == 0) {
904*11230Sgdamore@opensolaris.org 				rv = print_control(NULL, d, cinfop, verbose);
905*11230Sgdamore@opensolaris.org 				rval = rval ? rval : rv;
906*11230Sgdamore@opensolaris.org 				break;
907*11230Sgdamore@opensolaris.org 			}
908*11230Sgdamore@opensolaris.org 		}
909*11230Sgdamore@opensolaris.org 		/* Didn't find requested control */
910*11230Sgdamore@opensolaris.org 		if (j == d->cmax) {
911*11230Sgdamore@opensolaris.org 			warn(_("No such control: %s\n"), argv[i]);
912*11230Sgdamore@opensolaris.org 			rval = rval ? rval : ENODEV;
913*11230Sgdamore@opensolaris.org 		}
914*11230Sgdamore@opensolaris.org 	}
915*11230Sgdamore@opensolaris.org 
916*11230Sgdamore@opensolaris.org 	return (rval);
917*11230Sgdamore@opensolaris.org }
918*11230Sgdamore@opensolaris.org 
919*11230Sgdamore@opensolaris.org int
920*11230Sgdamore@opensolaris.org do_set_control(int argc, char **argv)
921*11230Sgdamore@opensolaris.org {
922*11230Sgdamore@opensolaris.org 	int		optc;
923*11230Sgdamore@opensolaris.org 	int		rval = 0;
924*11230Sgdamore@opensolaris.org 	int		verbose = 0;
925*11230Sgdamore@opensolaris.org 	device_t	*d;
926*11230Sgdamore@opensolaris.org 	char		*devname = NULL;
927*11230Sgdamore@opensolaris.org 	char		*cname;
928*11230Sgdamore@opensolaris.org 	char		*value;
929*11230Sgdamore@opensolaris.org 	int		i;
930*11230Sgdamore@opensolaris.org 	int		found;
931*11230Sgdamore@opensolaris.org 	int		rv;
932*11230Sgdamore@opensolaris.org 	char		*n;
933*11230Sgdamore@opensolaris.org 	cinfo_t		*cinfop;
934*11230Sgdamore@opensolaris.org 
935*11230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:v")) != EOF) {
936*11230Sgdamore@opensolaris.org 		switch (optc) {
937*11230Sgdamore@opensolaris.org 		case 'd':
938*11230Sgdamore@opensolaris.org 			devname = optarg;
939*11230Sgdamore@opensolaris.org 			break;
940*11230Sgdamore@opensolaris.org 		case 'v':
941*11230Sgdamore@opensolaris.org 			verbose = 1;
942*11230Sgdamore@opensolaris.org 			break;
943*11230Sgdamore@opensolaris.org 		default:
944*11230Sgdamore@opensolaris.org 			help();
945*11230Sgdamore@opensolaris.org 			return (-1);
946*11230Sgdamore@opensolaris.org 		}
947*11230Sgdamore@opensolaris.org 	}
948*11230Sgdamore@opensolaris.org 	argc -= optind;
949*11230Sgdamore@opensolaris.org 	argv += optind;
950*11230Sgdamore@opensolaris.org 
951*11230Sgdamore@opensolaris.org 	if (argc != 2) {
952*11230Sgdamore@opensolaris.org 		help();
953*11230Sgdamore@opensolaris.org 		return (-1);
954*11230Sgdamore@opensolaris.org 	}
955*11230Sgdamore@opensolaris.org 	cname = argv[0];
956*11230Sgdamore@opensolaris.org 	value = argv[1];
957*11230Sgdamore@opensolaris.org 
958*11230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
959*11230Sgdamore@opensolaris.org 		return (ENODEV);
960*11230Sgdamore@opensolaris.org 	}
961*11230Sgdamore@opensolaris.org 
962*11230Sgdamore@opensolaris.org 	for (i = 0, found = 0; i < d->cmax; i++) {
963*11230Sgdamore@opensolaris.org 		cinfop = &d->controls[i];
964*11230Sgdamore@opensolaris.org 		n = strrchr(cinfop->ci.extname, '_');
965*11230Sgdamore@opensolaris.org 		n = n ? n + 1 : cinfop->ci.extname;
966*11230Sgdamore@opensolaris.org 		if (strcmp(cname, n) != 0) {
967*11230Sgdamore@opensolaris.org 			continue;
968*11230Sgdamore@opensolaris.org 		}
969*11230Sgdamore@opensolaris.org 		found = 1;
970*11230Sgdamore@opensolaris.org 		rv = set_device_control(d, cinfop, value, verbose);
971*11230Sgdamore@opensolaris.org 		rval = rval ? rval : rv;
972*11230Sgdamore@opensolaris.org 	}
973*11230Sgdamore@opensolaris.org 	if (!found) {
974*11230Sgdamore@opensolaris.org 		warn(_("No such control: %s\n"), cname);
975*11230Sgdamore@opensolaris.org 	}
976*11230Sgdamore@opensolaris.org 
977*11230Sgdamore@opensolaris.org 	return (rval);
978*11230Sgdamore@opensolaris.org }
979*11230Sgdamore@opensolaris.org 
980*11230Sgdamore@opensolaris.org int
981*11230Sgdamore@opensolaris.org do_save_controls(int argc, char **argv)
982*11230Sgdamore@opensolaris.org {
983*11230Sgdamore@opensolaris.org 	int		optc;
984*11230Sgdamore@opensolaris.org 	int		rval = 0;
985*11230Sgdamore@opensolaris.org 	device_t	*d;
986*11230Sgdamore@opensolaris.org 	char		*devname = NULL;
987*11230Sgdamore@opensolaris.org 	char		*fname;
988*11230Sgdamore@opensolaris.org 	int		i;
989*11230Sgdamore@opensolaris.org 	int		rv;
990*11230Sgdamore@opensolaris.org 	cinfo_t		*cinfop;
991*11230Sgdamore@opensolaris.org 	FILE		*fp;
992*11230Sgdamore@opensolaris.org 	int		fd;
993*11230Sgdamore@opensolaris.org 	int		mode;
994*11230Sgdamore@opensolaris.org 
995*11230Sgdamore@opensolaris.org 	mode = O_WRONLY | O_CREAT | O_EXCL;
996*11230Sgdamore@opensolaris.org 
997*11230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:f")) != EOF) {
998*11230Sgdamore@opensolaris.org 		switch (optc) {
999*11230Sgdamore@opensolaris.org 		case 'd':
1000*11230Sgdamore@opensolaris.org 			devname = optarg;
1001*11230Sgdamore@opensolaris.org 			break;
1002*11230Sgdamore@opensolaris.org 		case 'f':
1003*11230Sgdamore@opensolaris.org 			mode &= ~O_EXCL;
1004*11230Sgdamore@opensolaris.org 			mode |= O_TRUNC;
1005*11230Sgdamore@opensolaris.org 			break;
1006*11230Sgdamore@opensolaris.org 		default:
1007*11230Sgdamore@opensolaris.org 			help();
1008*11230Sgdamore@opensolaris.org 			return (-1);
1009*11230Sgdamore@opensolaris.org 		}
1010*11230Sgdamore@opensolaris.org 	}
1011*11230Sgdamore@opensolaris.org 	argc -= optind;
1012*11230Sgdamore@opensolaris.org 	argv += optind;
1013*11230Sgdamore@opensolaris.org 
1014*11230Sgdamore@opensolaris.org 	if (argc != 1) {
1015*11230Sgdamore@opensolaris.org 		help();
1016*11230Sgdamore@opensolaris.org 		return (-1);
1017*11230Sgdamore@opensolaris.org 	}
1018*11230Sgdamore@opensolaris.org 	fname = argv[0];
1019*11230Sgdamore@opensolaris.org 
1020*11230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
1021*11230Sgdamore@opensolaris.org 		return (ENODEV);
1022*11230Sgdamore@opensolaris.org 	}
1023*11230Sgdamore@opensolaris.org 
1024*11230Sgdamore@opensolaris.org 	if ((fd = open(fname, mode, 0666)) < 0) {
1025*11230Sgdamore@opensolaris.org 		perror(_("Failed to create file"));
1026*11230Sgdamore@opensolaris.org 		return (errno);
1027*11230Sgdamore@opensolaris.org 	}
1028*11230Sgdamore@opensolaris.org 
1029*11230Sgdamore@opensolaris.org 	if ((fp = fdopen(fd, "w")) == NULL) {
1030*11230Sgdamore@opensolaris.org 		perror(_("Unable to open file\n"));
1031*11230Sgdamore@opensolaris.org 		(void) close(fd);
1032*11230Sgdamore@opensolaris.org 		(void) unlink(fname);
1033*11230Sgdamore@opensolaris.org 		return (errno);
1034*11230Sgdamore@opensolaris.org 	}
1035*11230Sgdamore@opensolaris.org 
1036*11230Sgdamore@opensolaris.org 	(void) fprintf(fp, "# Device: %s\n", d->mixer.devnode);
1037*11230Sgdamore@opensolaris.org 	(void) fprintf(fp, "# Name    = %s\n", d->card.shortname);
1038*11230Sgdamore@opensolaris.org 	(void) fprintf(fp, "# Config  = %s\n", d->card.longname);
1039*11230Sgdamore@opensolaris.org 
1040*11230Sgdamore@opensolaris.org 	if (strlen(d->card.hw_info)) {
1041*11230Sgdamore@opensolaris.org 		(void) fprintf(fp, "# HW Info = %s", d->card.hw_info);
1042*11230Sgdamore@opensolaris.org 	}
1043*11230Sgdamore@opensolaris.org 	(void) fprintf(fp, "#\n");
1044*11230Sgdamore@opensolaris.org 
1045*11230Sgdamore@opensolaris.org 	print_header(fp, 0);
1046*11230Sgdamore@opensolaris.org 
1047*11230Sgdamore@opensolaris.org 	for (i = 0; i < d->cmax; i++) {
1048*11230Sgdamore@opensolaris.org 		cinfop = &d->controls[i];
1049*11230Sgdamore@opensolaris.org 		rv = print_control(fp, d, cinfop, 0);
1050*11230Sgdamore@opensolaris.org 		rval = rval ? rval : rv;
1051*11230Sgdamore@opensolaris.org 	}
1052*11230Sgdamore@opensolaris.org 
1053*11230Sgdamore@opensolaris.org 	(void) fclose(fp);
1054*11230Sgdamore@opensolaris.org 
1055*11230Sgdamore@opensolaris.org 	return (rval);
1056*11230Sgdamore@opensolaris.org }
1057*11230Sgdamore@opensolaris.org 
1058*11230Sgdamore@opensolaris.org int
1059*11230Sgdamore@opensolaris.org do_load_controls(int argc, char **argv)
1060*11230Sgdamore@opensolaris.org {
1061*11230Sgdamore@opensolaris.org 	int	optc;
1062*11230Sgdamore@opensolaris.org 	int	rval = 0;
1063*11230Sgdamore@opensolaris.org 	device_t	*d;
1064*11230Sgdamore@opensolaris.org 	char		*devname = NULL;
1065*11230Sgdamore@opensolaris.org 	char	*fname;
1066*11230Sgdamore@opensolaris.org 	char	*cname;
1067*11230Sgdamore@opensolaris.org 	char	*value;
1068*11230Sgdamore@opensolaris.org 	int	i;
1069*11230Sgdamore@opensolaris.org 	int	rv;
1070*11230Sgdamore@opensolaris.org 	cinfo_t	*cinfop;
1071*11230Sgdamore@opensolaris.org 	FILE	*fp;
1072*11230Sgdamore@opensolaris.org 	char	linebuf[MAXLINE];
1073*11230Sgdamore@opensolaris.org 	int	lineno = 0;
1074*11230Sgdamore@opensolaris.org 	int	found;
1075*11230Sgdamore@opensolaris.org 
1076*11230Sgdamore@opensolaris.org 	while ((optc = getopt(argc, argv, "d:")) != EOF) {
1077*11230Sgdamore@opensolaris.org 		switch (optc) {
1078*11230Sgdamore@opensolaris.org 		case 'd':
1079*11230Sgdamore@opensolaris.org 			devname = optarg;
1080*11230Sgdamore@opensolaris.org 			break;
1081*11230Sgdamore@opensolaris.org 		default:
1082*11230Sgdamore@opensolaris.org 			help();
1083*11230Sgdamore@opensolaris.org 			return (-1);
1084*11230Sgdamore@opensolaris.org 		}
1085*11230Sgdamore@opensolaris.org 	}
1086*11230Sgdamore@opensolaris.org 	argc -= optind;
1087*11230Sgdamore@opensolaris.org 	argv += optind;
1088*11230Sgdamore@opensolaris.org 
1089*11230Sgdamore@opensolaris.org 	if (argc != 1) {
1090*11230Sgdamore@opensolaris.org 		help();
1091*11230Sgdamore@opensolaris.org 		return (-1);
1092*11230Sgdamore@opensolaris.org 	}
1093*11230Sgdamore@opensolaris.org 	fname = argv[0];
1094*11230Sgdamore@opensolaris.org 
1095*11230Sgdamore@opensolaris.org 	if ((d = find_device(devname)) == NULL) {
1096*11230Sgdamore@opensolaris.org 		return (ENODEV);
1097*11230Sgdamore@opensolaris.org 	}
1098*11230Sgdamore@opensolaris.org 
1099*11230Sgdamore@opensolaris.org 	if ((fp = fopen(fname, "r")) == NULL) {
1100*11230Sgdamore@opensolaris.org 		perror(_("Unable to open file"));
1101*11230Sgdamore@opensolaris.org 		return (errno);
1102*11230Sgdamore@opensolaris.org 	}
1103*11230Sgdamore@opensolaris.org 
1104*11230Sgdamore@opensolaris.org 	while (fgets(linebuf, sizeof (linebuf), fp) != NULL) {
1105*11230Sgdamore@opensolaris.org 		lineno++;
1106*11230Sgdamore@opensolaris.org 		if (linebuf[strlen(linebuf) - 1] != '\n') {
1107*11230Sgdamore@opensolaris.org 			warn(_("Warning: line too long at line %d\n"), lineno);
1108*11230Sgdamore@opensolaris.org 			/* read in the rest of the line and discard it */
1109*11230Sgdamore@opensolaris.org 			while (fgets(linebuf, sizeof (linebuf), fp) != NULL &&
1110*11230Sgdamore@opensolaris.org 			    (linebuf[strlen(linebuf) - 1] != '\n')) {
1111*11230Sgdamore@opensolaris.org 				continue;
1112*11230Sgdamore@opensolaris.org 			}
1113*11230Sgdamore@opensolaris.org 			continue;
1114*11230Sgdamore@opensolaris.org 		}
1115*11230Sgdamore@opensolaris.org 
1116*11230Sgdamore@opensolaris.org 		/* we have a good line ... */
1117*11230Sgdamore@opensolaris.org 		cname = strtok(linebuf, " \t\n");
1118*11230Sgdamore@opensolaris.org 		/* skip comments and blank lines */
1119*11230Sgdamore@opensolaris.org 		if ((cname == NULL) || (cname[0] == '#')) {
1120*11230Sgdamore@opensolaris.org 			continue;
1121*11230Sgdamore@opensolaris.org 		}
1122*11230Sgdamore@opensolaris.org 		value = strtok(NULL, " \t\n");
1123*11230Sgdamore@opensolaris.org 		if ((value == NULL) || (*cname == 0)) {
1124*11230Sgdamore@opensolaris.org 			warn(_("Warning: missing value at line %d\n"), lineno);
1125*11230Sgdamore@opensolaris.org 			continue;
1126*11230Sgdamore@opensolaris.org 		}
1127*11230Sgdamore@opensolaris.org 
1128*11230Sgdamore@opensolaris.org 		for (i = 0, found = 0; i < d->cmax; i++) {
1129*11230Sgdamore@opensolaris.org 			/* save and restore requires an exact match */
1130*11230Sgdamore@opensolaris.org 			cinfop = &d->controls[i];
1131*11230Sgdamore@opensolaris.org 			if (strcmp(cinfop->ci.extname, cname) != 0) {
1132*11230Sgdamore@opensolaris.org 				continue;
1133*11230Sgdamore@opensolaris.org 			}
1134*11230Sgdamore@opensolaris.org 			found = 1;
1135*11230Sgdamore@opensolaris.org 			rv = set_device_control(d, cinfop, value, 0);
1136*11230Sgdamore@opensolaris.org 			rval = rval ? rval : rv;
1137*11230Sgdamore@opensolaris.org 		}
1138*11230Sgdamore@opensolaris.org 		if (!found) {
1139*11230Sgdamore@opensolaris.org 			warn(_("No such control: %s\n"), cname);
1140*11230Sgdamore@opensolaris.org 		}
1141*11230Sgdamore@opensolaris.org 	}
1142*11230Sgdamore@opensolaris.org 	(void) fclose(fp);
1143*11230Sgdamore@opensolaris.org 
1144*11230Sgdamore@opensolaris.org 	return (rval);
1145*11230Sgdamore@opensolaris.org }
1146*11230Sgdamore@opensolaris.org 
1147*11230Sgdamore@opensolaris.org int
1148*11230Sgdamore@opensolaris.org main(int argc, char **argv)
1149*11230Sgdamore@opensolaris.org {
1150*11230Sgdamore@opensolaris.org 	int rv = 0;
1151*11230Sgdamore@opensolaris.org 	int opt;
1152*11230Sgdamore@opensolaris.org 
1153*11230Sgdamore@opensolaris.org 	(void) setlocale(LC_ALL, "");
1154*11230Sgdamore@opensolaris.org 	(void) textdomain(TEXT_DOMAIN);
1155*11230Sgdamore@opensolaris.org 
1156*11230Sgdamore@opensolaris.org 	while ((opt = getopt(argc, argv, "h")) != EOF) {
1157*11230Sgdamore@opensolaris.org 		switch (opt) {
1158*11230Sgdamore@opensolaris.org 		case 'h':
1159*11230Sgdamore@opensolaris.org 			help();
1160*11230Sgdamore@opensolaris.org 			rv = 0;
1161*11230Sgdamore@opensolaris.org 			goto OUT;
1162*11230Sgdamore@opensolaris.org 		default:
1163*11230Sgdamore@opensolaris.org 			rv = EINVAL;
1164*11230Sgdamore@opensolaris.org 			break;
1165*11230Sgdamore@opensolaris.org 		}
1166*11230Sgdamore@opensolaris.org 	}
1167*11230Sgdamore@opensolaris.org 
1168*11230Sgdamore@opensolaris.org 	if (rv) {
1169*11230Sgdamore@opensolaris.org 		goto OUT;
1170*11230Sgdamore@opensolaris.org 	}
1171*11230Sgdamore@opensolaris.org 
1172*11230Sgdamore@opensolaris.org 	argc -= optind;
1173*11230Sgdamore@opensolaris.org 	argv += optind;
1174*11230Sgdamore@opensolaris.org 
1175*11230Sgdamore@opensolaris.org 	rv = load_devices();
1176*11230Sgdamore@opensolaris.org 	if (rv != 0) {
1177*11230Sgdamore@opensolaris.org 		goto OUT;
1178*11230Sgdamore@opensolaris.org 	}
1179*11230Sgdamore@opensolaris.org 
1180*11230Sgdamore@opensolaris.org 	if (argc < 1) {
1181*11230Sgdamore@opensolaris.org 		help();
1182*11230Sgdamore@opensolaris.org 		rv = EINVAL;
1183*11230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "help") == 0) {
1184*11230Sgdamore@opensolaris.org 		help();
1185*11230Sgdamore@opensolaris.org 		rv = 0;
1186*11230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "list-devices") == 0) {
1187*11230Sgdamore@opensolaris.org 		rv = do_list_devices(argc, argv);
1188*11230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "show-device") == 0) {
1189*11230Sgdamore@opensolaris.org 		rv = do_show_device(argc, argv);
1190*11230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "show-control") == 0) {
1191*11230Sgdamore@opensolaris.org 		rv = do_show_control(argc, argv);
1192*11230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "set-control") == 0) {
1193*11230Sgdamore@opensolaris.org 		rv = do_set_control(argc, argv);
1194*11230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "load-controls") == 0) {
1195*11230Sgdamore@opensolaris.org 		rv = do_load_controls(argc, argv);
1196*11230Sgdamore@opensolaris.org 	} else if (strcmp(argv[0], "save-controls") == 0) {
1197*11230Sgdamore@opensolaris.org 		rv = do_save_controls(argc, argv);
1198*11230Sgdamore@opensolaris.org 	} else {
1199*11230Sgdamore@opensolaris.org 		help();
1200*11230Sgdamore@opensolaris.org 		rv = EINVAL;
1201*11230Sgdamore@opensolaris.org 	}
1202*11230Sgdamore@opensolaris.org 
1203*11230Sgdamore@opensolaris.org OUT:
1204*11230Sgdamore@opensolaris.org 	free_devices();
1205*11230Sgdamore@opensolaris.org 	return (rv);
1206*11230Sgdamore@opensolaris.org }
1207