xref: /onnv-gate/usr/src/uts/common/io/audio/impl/audio_oss.c (revision 12165:e481916a5729)
19484Sgarrett.damore@Sun.COM /*
29484Sgarrett.damore@Sun.COM  * CDDL HEADER START
39484Sgarrett.damore@Sun.COM  *
49484Sgarrett.damore@Sun.COM  * The contents of this file are subject to the terms of the
59484Sgarrett.damore@Sun.COM  * Common Development and Distribution License (the "License").
69484Sgarrett.damore@Sun.COM  * You may not use this file except in compliance with the License.
79484Sgarrett.damore@Sun.COM  *
89484Sgarrett.damore@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99484Sgarrett.damore@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109484Sgarrett.damore@Sun.COM  * See the License for the specific language governing permissions
119484Sgarrett.damore@Sun.COM  * and limitations under the License.
129484Sgarrett.damore@Sun.COM  *
139484Sgarrett.damore@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149484Sgarrett.damore@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159484Sgarrett.damore@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169484Sgarrett.damore@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179484Sgarrett.damore@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189484Sgarrett.damore@Sun.COM  *
199484Sgarrett.damore@Sun.COM  * CDDL HEADER END
209484Sgarrett.damore@Sun.COM  */
219484Sgarrett.damore@Sun.COM /*
22*12165Sgdamore@opensolaris.org  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
239484Sgarrett.damore@Sun.COM  */
249484Sgarrett.damore@Sun.COM 
259484Sgarrett.damore@Sun.COM #include <sys/types.h>
269484Sgarrett.damore@Sun.COM #include <sys/open.h>
279484Sgarrett.damore@Sun.COM #include <sys/errno.h>
289484Sgarrett.damore@Sun.COM #include <sys/ddi.h>
299484Sgarrett.damore@Sun.COM #include <sys/sunddi.h>
309484Sgarrett.damore@Sun.COM #include <sys/audio/audio_oss.h>
319484Sgarrett.damore@Sun.COM #include <sys/file.h>
329484Sgarrett.damore@Sun.COM #include <sys/note.h>
339484Sgarrett.damore@Sun.COM #include <sys/sysmacros.h>
349484Sgarrett.damore@Sun.COM #include <sys/list.h>
359484Sgarrett.damore@Sun.COM #include "audio_client.h"
369484Sgarrett.damore@Sun.COM 
379484Sgarrett.damore@Sun.COM #define	OSS_FMT		AFMT_S16_LE
389484Sgarrett.damore@Sun.COM #define	OSS_RATE	48000
399484Sgarrett.damore@Sun.COM #define	OSS_CHANNELS	2
409484Sgarrett.damore@Sun.COM 
419484Sgarrett.damore@Sun.COM typedef struct ossclient ossclient_t;
429484Sgarrett.damore@Sun.COM typedef struct ossdev ossdev_t;
439484Sgarrett.damore@Sun.COM 
449484Sgarrett.damore@Sun.COM static const struct {
459484Sgarrett.damore@Sun.COM 	int	oss;
469484Sgarrett.damore@Sun.COM 	int	fmt;
479484Sgarrett.damore@Sun.COM } oss_formats[] = {
489484Sgarrett.damore@Sun.COM 	{ AFMT_MU_LAW,		AUDIO_FORMAT_ULAW },
499484Sgarrett.damore@Sun.COM 	{ AFMT_A_LAW,		AUDIO_FORMAT_ALAW },
509484Sgarrett.damore@Sun.COM 	{ AFMT_U8,		AUDIO_FORMAT_U8 },
519484Sgarrett.damore@Sun.COM 	{ AFMT_S8,		AUDIO_FORMAT_S8 },
529484Sgarrett.damore@Sun.COM 	{ AFMT_S16_BE,		AUDIO_FORMAT_S16_BE },
539484Sgarrett.damore@Sun.COM 	{ AFMT_S16_LE,		AUDIO_FORMAT_S16_LE },
549484Sgarrett.damore@Sun.COM 	{ AFMT_U16_BE,		AUDIO_FORMAT_U16_BE },
559484Sgarrett.damore@Sun.COM 	{ AFMT_U16_LE,		AUDIO_FORMAT_U16_LE },
569484Sgarrett.damore@Sun.COM 	{ AFMT_S24_BE,		AUDIO_FORMAT_S24_BE },
579484Sgarrett.damore@Sun.COM 	{ AFMT_S24_LE,		AUDIO_FORMAT_S24_LE },
589484Sgarrett.damore@Sun.COM 	{ AFMT_S32_BE,		AUDIO_FORMAT_S32_BE },
599484Sgarrett.damore@Sun.COM 	{ AFMT_S32_LE,		AUDIO_FORMAT_S32_LE },
609484Sgarrett.damore@Sun.COM 	{ AFMT_S24_PACKED,	AUDIO_FORMAT_S24_PACKED },
619484Sgarrett.damore@Sun.COM 	{ AFMT_AC3,		AUDIO_FORMAT_AC3 },
629484Sgarrett.damore@Sun.COM 	{ AFMT_QUERY,		AUDIO_FORMAT_NONE }
639484Sgarrett.damore@Sun.COM };
649484Sgarrett.damore@Sun.COM 
659484Sgarrett.damore@Sun.COM /* common structure shared between both mixer and dsp nodes */
669484Sgarrett.damore@Sun.COM struct ossclient {
679484Sgarrett.damore@Sun.COM 	ossdev_t		*o_ossdev;
689484Sgarrett.damore@Sun.COM 	audio_client_t		*o_client;
699484Sgarrett.damore@Sun.COM 	/* sndstat */
709484Sgarrett.damore@Sun.COM 	kmutex_t		o_ss_lock;
719484Sgarrett.damore@Sun.COM 	char			*o_ss_buf;
729484Sgarrett.damore@Sun.COM 	size_t			o_ss_len;
739484Sgarrett.damore@Sun.COM 	size_t			o_ss_sz;
749484Sgarrett.damore@Sun.COM 	size_t			o_ss_off;
759484Sgarrett.damore@Sun.COM };
769484Sgarrett.damore@Sun.COM 
779484Sgarrett.damore@Sun.COM struct ossdev {
789484Sgarrett.damore@Sun.COM 	audio_dev_t		*d_dev;
799484Sgarrett.damore@Sun.COM 
809484Sgarrett.damore@Sun.COM 	uint_t			d_nctrl;	/* num actual controls */
819484Sgarrett.damore@Sun.COM 	uint_t			d_nalloc;	/* num allocated controls */
829484Sgarrett.damore@Sun.COM 	audio_ctrl_t		**d_ctrls;	/* array of control handles */
839484Sgarrett.damore@Sun.COM 	oss_mixext		*d_exts;	/* array of mixer descs */
849484Sgarrett.damore@Sun.COM 
859484Sgarrett.damore@Sun.COM 	int			d_play_grp;
869484Sgarrett.damore@Sun.COM 	int			d_rec_grp;
879484Sgarrett.damore@Sun.COM 	int			d_mon_grp;
889484Sgarrett.damore@Sun.COM 	int			d_misc_grp;
899484Sgarrett.damore@Sun.COM 
909484Sgarrett.damore@Sun.COM 	kmutex_t		d_mx;
919484Sgarrett.damore@Sun.COM 	kcondvar_t		d_cv;
929484Sgarrett.damore@Sun.COM };
939484Sgarrett.damore@Sun.COM 
949484Sgarrett.damore@Sun.COM static int
oss_cnt_controls(audio_ctrl_t * ctrl,void * arg)959484Sgarrett.damore@Sun.COM oss_cnt_controls(audio_ctrl_t *ctrl, void *arg)
969484Sgarrett.damore@Sun.COM {
979484Sgarrett.damore@Sun.COM 	int			*pint = (int *)arg;
989484Sgarrett.damore@Sun.COM 	int			cnt;
999484Sgarrett.damore@Sun.COM 	audio_ctrl_desc_t	desc;
1009484Sgarrett.damore@Sun.COM 
1019484Sgarrett.damore@Sun.COM 	cnt = *pint;
1029484Sgarrett.damore@Sun.COM 	cnt++;
1039484Sgarrett.damore@Sun.COM 	*pint = cnt;
1049484Sgarrett.damore@Sun.COM 
1059484Sgarrett.damore@Sun.COM 	if (auclnt_control_describe(ctrl, &desc) != 0)
1069484Sgarrett.damore@Sun.COM 		return (AUDIO_WALK_CONTINUE);
1079484Sgarrett.damore@Sun.COM 
1089484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) {
1099484Sgarrett.damore@Sun.COM 		for (uint64_t mask = desc.acd_maxvalue; mask; mask >>= 1) {
1109484Sgarrett.damore@Sun.COM 			if (mask & 1) {
1119484Sgarrett.damore@Sun.COM 				cnt++;
1129484Sgarrett.damore@Sun.COM 			}
1139484Sgarrett.damore@Sun.COM 		}
1149484Sgarrett.damore@Sun.COM 		*pint = cnt;
1159484Sgarrett.damore@Sun.COM 	}
1169484Sgarrett.damore@Sun.COM 
1179484Sgarrett.damore@Sun.COM 	return (AUDIO_WALK_CONTINUE);
1189484Sgarrett.damore@Sun.COM }
1199484Sgarrett.damore@Sun.COM 
1209484Sgarrett.damore@Sun.COM /*
1219484Sgarrett.damore@Sun.COM  * Add one entry to the OSS user control table to internal control
1229484Sgarrett.damore@Sun.COM  * helper table.
1239484Sgarrett.damore@Sun.COM  *
1249484Sgarrett.damore@Sun.COM  * This is used with auimpl_walk_controls. The table must be pre-
1259484Sgarrett.damore@Sun.COM  * allocated before it is walk'd. This includes the root and
1269484Sgarrett.damore@Sun.COM  * extended control markers!
1279484Sgarrett.damore@Sun.COM  */
1289484Sgarrett.damore@Sun.COM static int
oss_add_control(audio_ctrl_t * ctrl,void * arg)1299484Sgarrett.damore@Sun.COM oss_add_control(audio_ctrl_t *ctrl, void *arg)
1309484Sgarrett.damore@Sun.COM {
1319484Sgarrett.damore@Sun.COM 	ossdev_t		*odev = arg;
1329484Sgarrett.damore@Sun.COM 	audio_ctrl_desc_t	desc;
1339484Sgarrett.damore@Sun.COM 	oss_mixext		*ext;
1349484Sgarrett.damore@Sun.COM 	int			bit;
1359484Sgarrett.damore@Sun.COM 	uint64_t		mask;
1369484Sgarrett.damore@Sun.COM 	const char		*name;
1379484Sgarrett.damore@Sun.COM 	int			parent;
1389484Sgarrett.damore@Sun.COM 	int			flags;
1399484Sgarrett.damore@Sun.COM 	unsigned		scope;
1409484Sgarrett.damore@Sun.COM 
1419484Sgarrett.damore@Sun.COM 	if (auclnt_control_describe(ctrl, &desc))
1429484Sgarrett.damore@Sun.COM 		return (AUDIO_WALK_CONTINUE);
1439484Sgarrett.damore@Sun.COM 
1449484Sgarrett.damore@Sun.COM 	parent = 0;
1459484Sgarrett.damore@Sun.COM 
1469484Sgarrett.damore@Sun.COM 	/*
1479484Sgarrett.damore@Sun.COM 	 * Add appropriate group if not already done so.
1489484Sgarrett.damore@Sun.COM 	 */
1499484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_PLAY) {
1509484Sgarrett.damore@Sun.COM 		if (!odev->d_play_grp) {
1519484Sgarrett.damore@Sun.COM 			ext = &odev->d_exts[odev->d_nctrl];
1529484Sgarrett.damore@Sun.COM 			ext->ctrl = odev->d_nctrl;
1539484Sgarrett.damore@Sun.COM 			ext->control_no = -1;
1549484Sgarrett.damore@Sun.COM 			ext->type = MIXT_GROUP;
1559484Sgarrett.damore@Sun.COM 			ext->desc = MIXEXT_SCOPE_OUTPUT;
1569484Sgarrett.damore@Sun.COM 			ext->timestamp = gethrtime();
1579484Sgarrett.damore@Sun.COM 			(void) snprintf(ext->id, sizeof (ext->id), "PLAYBACK");
1589484Sgarrett.damore@Sun.COM 			odev->d_play_grp = odev->d_nctrl;
1599484Sgarrett.damore@Sun.COM 			odev->d_nctrl++;
1609484Sgarrett.damore@Sun.COM 		}
1619484Sgarrett.damore@Sun.COM 		scope = MIXEXT_SCOPE_OUTPUT;
1629484Sgarrett.damore@Sun.COM 		parent = odev->d_play_grp;
1639484Sgarrett.damore@Sun.COM 	} else if (desc.acd_flags & AUDIO_CTRL_FLAG_REC) {
1649484Sgarrett.damore@Sun.COM 		if (!odev->d_rec_grp) {
1659484Sgarrett.damore@Sun.COM 			ext = &odev->d_exts[odev->d_nctrl];
1669484Sgarrett.damore@Sun.COM 			ext->ctrl = odev->d_nctrl;
1679484Sgarrett.damore@Sun.COM 			ext->control_no = -1;
1689484Sgarrett.damore@Sun.COM 			ext->type = MIXT_GROUP;
1699484Sgarrett.damore@Sun.COM 			ext->desc = MIXEXT_SCOPE_INPUT;
1709484Sgarrett.damore@Sun.COM 			ext->timestamp = gethrtime();
1719484Sgarrett.damore@Sun.COM 			(void) snprintf(ext->id, sizeof (ext->id), "RECORD");
1729484Sgarrett.damore@Sun.COM 			odev->d_rec_grp = odev->d_nctrl;
1739484Sgarrett.damore@Sun.COM 			odev->d_nctrl++;
1749484Sgarrett.damore@Sun.COM 		}
1759484Sgarrett.damore@Sun.COM 		scope = MIXEXT_SCOPE_INPUT;
1769484Sgarrett.damore@Sun.COM 		parent = odev->d_rec_grp;
1779484Sgarrett.damore@Sun.COM 	} else if (desc.acd_flags & AUDIO_CTRL_FLAG_MONITOR) {
1789484Sgarrett.damore@Sun.COM 		if (!odev->d_mon_grp) {
1799484Sgarrett.damore@Sun.COM 			ext = &odev->d_exts[odev->d_nctrl];
1809484Sgarrett.damore@Sun.COM 			ext->ctrl = odev->d_nctrl;
1819484Sgarrett.damore@Sun.COM 			ext->control_no = -1;
1829484Sgarrett.damore@Sun.COM 			ext->type = MIXT_GROUP;
1839484Sgarrett.damore@Sun.COM 			ext->desc = MIXEXT_SCOPE_MONITOR;
1849484Sgarrett.damore@Sun.COM 			ext->timestamp = gethrtime();
1859484Sgarrett.damore@Sun.COM 			(void) snprintf(ext->id, sizeof (ext->id), "MONITOR");
1869484Sgarrett.damore@Sun.COM 			odev->d_mon_grp = odev->d_nctrl;
1879484Sgarrett.damore@Sun.COM 			odev->d_nctrl++;
1889484Sgarrett.damore@Sun.COM 		}
1899484Sgarrett.damore@Sun.COM 		scope = MIXEXT_SCOPE_MONITOR;
1909484Sgarrett.damore@Sun.COM 		parent = odev->d_mon_grp;
1919484Sgarrett.damore@Sun.COM 	} else {
1929484Sgarrett.damore@Sun.COM 		if (!odev->d_misc_grp) {
1939484Sgarrett.damore@Sun.COM 			ext = &odev->d_exts[odev->d_nctrl];
1949484Sgarrett.damore@Sun.COM 			ext->ctrl = odev->d_nctrl;
1959484Sgarrett.damore@Sun.COM 			ext->control_no = -1;
1969484Sgarrett.damore@Sun.COM 			ext->type = MIXT_GROUP;
1979484Sgarrett.damore@Sun.COM 			ext->desc = MIXEXT_SCOPE_OTHER;
1989484Sgarrett.damore@Sun.COM 			ext->timestamp = gethrtime();
1999484Sgarrett.damore@Sun.COM 			(void) snprintf(ext->id, sizeof (ext->id), "MISC");
2009484Sgarrett.damore@Sun.COM 			odev->d_misc_grp = odev->d_nctrl;
2019484Sgarrett.damore@Sun.COM 			odev->d_nctrl++;
2029484Sgarrett.damore@Sun.COM 		}
2039484Sgarrett.damore@Sun.COM 		scope = MIXEXT_SCOPE_OTHER;
2049484Sgarrett.damore@Sun.COM 		parent = odev->d_misc_grp;
2059484Sgarrett.damore@Sun.COM 	}
2069484Sgarrett.damore@Sun.COM 
2079484Sgarrett.damore@Sun.COM 	name = desc.acd_name ? desc.acd_name : "";
2089484Sgarrett.damore@Sun.COM 
2099484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) {
2109484Sgarrett.damore@Sun.COM 		ext = &odev->d_exts[odev->d_nctrl];
2119484Sgarrett.damore@Sun.COM 		ext->ctrl = odev->d_nctrl;
2129484Sgarrett.damore@Sun.COM 		ext->control_no = -1;
2139484Sgarrett.damore@Sun.COM 		ext->type = MIXT_GROUP;
2149484Sgarrett.damore@Sun.COM 		ext->timestamp = gethrtime();
2159484Sgarrett.damore@Sun.COM 		ext->parent = parent;
2169484Sgarrett.damore@Sun.COM 		ext->desc = scope;
2179484Sgarrett.damore@Sun.COM 		(void) snprintf(ext->id, sizeof (ext->id), "%s", name);
2189484Sgarrett.damore@Sun.COM 		(void) snprintf(ext->extname, sizeof (ext->extname),
2199484Sgarrett.damore@Sun.COM 		    "%s", name);
2209484Sgarrett.damore@Sun.COM 		parent = odev->d_nctrl++;
2219484Sgarrett.damore@Sun.COM 	}
2229484Sgarrett.damore@Sun.COM 
2239484Sgarrett.damore@Sun.COM 	/* Next available open entry */
2249484Sgarrett.damore@Sun.COM 	ext = &odev->d_exts[odev->d_nctrl];
2259484Sgarrett.damore@Sun.COM 
2269484Sgarrett.damore@Sun.COM 	/* Record the underlying control handle */
2279484Sgarrett.damore@Sun.COM 	odev->d_ctrls[odev->d_nctrl] = ctrl;
2289484Sgarrett.damore@Sun.COM 
2299484Sgarrett.damore@Sun.COM 	/*
2309484Sgarrett.damore@Sun.COM 	 * Now setup the oss entry
2319484Sgarrett.damore@Sun.COM 	 */
2329484Sgarrett.damore@Sun.COM 
2339484Sgarrett.damore@Sun.COM 	ext->ctrl = odev->d_nctrl;
2349484Sgarrett.damore@Sun.COM 	ext->control_no = -1;
2359484Sgarrett.damore@Sun.COM 	ext->maxvalue = (int)desc.acd_maxvalue;
2369484Sgarrett.damore@Sun.COM 	ext->minvalue = (int)desc.acd_minvalue;
2379484Sgarrett.damore@Sun.COM 	ext->timestamp = gethrtime();
2389484Sgarrett.damore@Sun.COM 	ext->parent = parent;
2399484Sgarrett.damore@Sun.COM 	ext->desc = scope;
2409484Sgarrett.damore@Sun.COM 	/* all controls should be pollable for now */
2419484Sgarrett.damore@Sun.COM 	flags = MIXF_POLL;
2429484Sgarrett.damore@Sun.COM 
2439484Sgarrett.damore@Sun.COM 	/*
2449484Sgarrett.damore@Sun.COM 	 * The following flags are intended to help out applications
2459484Sgarrett.damore@Sun.COM 	 * which need to figure out where to place certain controls.
2469484Sgarrett.damore@Sun.COM 	 * A few further words of guidance:
2479484Sgarrett.damore@Sun.COM 	 *
2489484Sgarrett.damore@Sun.COM 	 * Apps that just want a single master volume control should
2499484Sgarrett.damore@Sun.COM 	 * adjust the control(s) that are labelled with MIXF_PCMVOL if
2509484Sgarrett.damore@Sun.COM 	 * present.  They can fall back to adjusting all MAINVOL
2519484Sgarrett.damore@Sun.COM 	 * levels instead, if no PCMVOL is present.
2529484Sgarrett.damore@Sun.COM 	 *
2539484Sgarrett.damore@Sun.COM 	 * Controls that are one type on a certain device might be a
2549484Sgarrett.damore@Sun.COM 	 * different type on another device.  For example,
2559484Sgarrett.damore@Sun.COM 	 * audiopci/ak4531 can adjust input gains for individual
2569484Sgarrett.damore@Sun.COM 	 * levels, but lacks a master record gain.  AC'97, on the
2579484Sgarrett.damore@Sun.COM 	 * other hand, has individual monitor gains for inputs, but
2589484Sgarrett.damore@Sun.COM 	 * only a single master recording gain.
2599484Sgarrett.damore@Sun.COM 	 */
2609484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_READABLE)
2619484Sgarrett.damore@Sun.COM 		flags |= MIXF_READABLE;
2629484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_WRITEABLE)
2639484Sgarrett.damore@Sun.COM 		flags |= MIXF_WRITEABLE;
2649484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_CENTIBEL)
2659484Sgarrett.damore@Sun.COM 		flags |= MIXF_CENTIBEL;
2669484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_DECIBEL)
2679484Sgarrett.damore@Sun.COM 		flags |= MIXF_DECIBEL;
2689484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_MAINVOL)
2699484Sgarrett.damore@Sun.COM 		flags |= MIXF_MAINVOL;
2709484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_PCMVOL)
2719484Sgarrett.damore@Sun.COM 		flags |= MIXF_PCMVOL;
2729484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_RECVOL)
2739484Sgarrett.damore@Sun.COM 		flags |= MIXF_RECVOL;
2749484Sgarrett.damore@Sun.COM 	if (desc.acd_flags & AUDIO_CTRL_FLAG_MONVOL)
2759484Sgarrett.damore@Sun.COM 		flags |= MIXF_MONVOL;
2769484Sgarrett.damore@Sun.COM 	ext->flags = flags;
2779484Sgarrett.damore@Sun.COM 
2789484Sgarrett.damore@Sun.COM 	(void) snprintf(ext->id, sizeof (ext->id), "%s", name);
2799484Sgarrett.damore@Sun.COM 
2809484Sgarrett.damore@Sun.COM 	/*
2819484Sgarrett.damore@Sun.COM 	 * For now just use the same extname as the real name.
2829484Sgarrett.damore@Sun.COM 	 */
2839484Sgarrett.damore@Sun.COM 	(void) snprintf(ext->extname, sizeof (ext->extname), name);
2849484Sgarrett.damore@Sun.COM 
2859484Sgarrett.damore@Sun.COM 	/*
2869484Sgarrett.damore@Sun.COM 	 * Now we deal with various control types.
2879484Sgarrett.damore@Sun.COM 	 */
2889484Sgarrett.damore@Sun.COM 	switch (desc.acd_type) {
2899484Sgarrett.damore@Sun.COM 	case AUDIO_CTRL_TYPE_BOOLEAN:
2909484Sgarrett.damore@Sun.COM 		ext->type = MIXT_ONOFF;
2919484Sgarrett.damore@Sun.COM 		ext->enumbit = -1;
2929484Sgarrett.damore@Sun.COM 		break;
2939484Sgarrett.damore@Sun.COM 	case AUDIO_CTRL_TYPE_STEREO:
2949484Sgarrett.damore@Sun.COM 		ext->type = MIXT_STEREOSLIDER;
2959484Sgarrett.damore@Sun.COM 		break;
2969484Sgarrett.damore@Sun.COM 	case AUDIO_CTRL_TYPE_MONO:
2979484Sgarrett.damore@Sun.COM 		ext->type = MIXT_MONOSLIDER;
2989484Sgarrett.damore@Sun.COM 		break;
2999484Sgarrett.damore@Sun.COM 	case AUDIO_CTRL_TYPE_ENUM:
3009484Sgarrett.damore@Sun.COM 
3019484Sgarrett.damore@Sun.COM 		if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) {
3029484Sgarrett.damore@Sun.COM 			/*
3039484Sgarrett.damore@Sun.COM 			 * We turn AUDIO_CTRL_FLAG_MULTI into a group
3049484Sgarrett.damore@Sun.COM 			 * of checkboxes, since OSS can't represent it
3059484Sgarrett.damore@Sun.COM 			 * natively.
3069484Sgarrett.damore@Sun.COM 			 */
3079484Sgarrett.damore@Sun.COM 			mask = desc.acd_maxvalue;
3089484Sgarrett.damore@Sun.COM 			bit = 0;
3099484Sgarrett.damore@Sun.COM 			while (mask) {
3109484Sgarrett.damore@Sun.COM 				if (mask & 1) {
3119484Sgarrett.damore@Sun.COM 					ext = &odev->d_exts[odev->d_nctrl];
3129484Sgarrett.damore@Sun.COM 					(void) snprintf(ext->extname,
3139484Sgarrett.damore@Sun.COM 					    sizeof (ext->extname), "%s.%s",
3149484Sgarrett.damore@Sun.COM 					    name, desc.acd_enum[bit]);
3159484Sgarrett.damore@Sun.COM 					(void) snprintf(ext->id,
3169484Sgarrett.damore@Sun.COM 					    sizeof (ext->id), "%s",
3179484Sgarrett.damore@Sun.COM 					    desc.acd_enum[bit]);
3189484Sgarrett.damore@Sun.COM 					ext->ctrl = odev->d_nctrl;
3199484Sgarrett.damore@Sun.COM 					ext->control_no = -1;
3209484Sgarrett.damore@Sun.COM 					ext->parent = parent;
3219484Sgarrett.damore@Sun.COM 					ext->timestamp = gethrtime();
3229484Sgarrett.damore@Sun.COM 					ext->type = MIXT_ONOFF;
3239484Sgarrett.damore@Sun.COM 					ext->minvalue = 0;
3249484Sgarrett.damore@Sun.COM 					ext->maxvalue = 1;
3259484Sgarrett.damore@Sun.COM 					ext->enumbit = bit;
3269484Sgarrett.damore@Sun.COM 					ext->flags = flags;
3279484Sgarrett.damore@Sun.COM 					odev->d_ctrls[odev->d_nctrl] = ctrl;
3289484Sgarrett.damore@Sun.COM 					odev->d_nctrl++;
3299484Sgarrett.damore@Sun.COM 				}
3309484Sgarrett.damore@Sun.COM 				bit++;
3319484Sgarrett.damore@Sun.COM 				mask >>= 1;
3329484Sgarrett.damore@Sun.COM 			}
3339484Sgarrett.damore@Sun.COM 			return (AUDIO_WALK_CONTINUE);
3349484Sgarrett.damore@Sun.COM 		} else {
3359484Sgarrett.damore@Sun.COM 			/*
3369484Sgarrett.damore@Sun.COM 			 * NB: This is sufficient only for controls
3379484Sgarrett.damore@Sun.COM 			 * with a single value.  It cannot express the
3389484Sgarrett.damore@Sun.COM 			 * richer bitmask capabilities.
3399484Sgarrett.damore@Sun.COM 			 */
3409484Sgarrett.damore@Sun.COM 			ext->type = MIXT_ENUM;
3419484Sgarrett.damore@Sun.COM 			ext->minvalue = 0;
3429484Sgarrett.damore@Sun.COM 
3439484Sgarrett.damore@Sun.COM 			/*
3449484Sgarrett.damore@Sun.COM 			 * For an enumaration, we need to figure out
3459484Sgarrett.damore@Sun.COM 			 * which values are present, and set the
3469484Sgarrett.damore@Sun.COM 			 * appropriate mask and max value.
3479484Sgarrett.damore@Sun.COM 			 */
3489484Sgarrett.damore@Sun.COM 			bzero(ext->enum_present, sizeof (ext->enum_present));
3499484Sgarrett.damore@Sun.COM 			mask = desc.acd_maxvalue;
3509484Sgarrett.damore@Sun.COM 			bit = 0;
3519484Sgarrett.damore@Sun.COM 			while (mask) {
3529484Sgarrett.damore@Sun.COM 				if (mask & 1) {
3539484Sgarrett.damore@Sun.COM 					ext->enum_present[bit / 8] |=
3549484Sgarrett.damore@Sun.COM 					    (1 << (bit % 8));
3559484Sgarrett.damore@Sun.COM 				}
3569484Sgarrett.damore@Sun.COM 				mask >>= 1;
3579484Sgarrett.damore@Sun.COM 				bit++;
3589484Sgarrett.damore@Sun.COM 			}
3599484Sgarrett.damore@Sun.COM 			ext->maxvalue = bit;
3609484Sgarrett.damore@Sun.COM 		}
3619484Sgarrett.damore@Sun.COM 		break;
3629484Sgarrett.damore@Sun.COM 
3639484Sgarrett.damore@Sun.COM 	case AUDIO_CTRL_TYPE_METER:
3649484Sgarrett.damore@Sun.COM 	default:
3659484Sgarrett.damore@Sun.COM 		/* Its an unknown or unsupported (for now) control, skip */
3669484Sgarrett.damore@Sun.COM 		return (AUDIO_WALK_CONTINUE);
3679484Sgarrett.damore@Sun.COM 	}
3689484Sgarrett.damore@Sun.COM 
3699484Sgarrett.damore@Sun.COM 	odev->d_nctrl++;
3709484Sgarrett.damore@Sun.COM 
3719484Sgarrett.damore@Sun.COM 	return (AUDIO_WALK_CONTINUE);
3729484Sgarrett.damore@Sun.COM }
3739484Sgarrett.damore@Sun.COM 
3749484Sgarrett.damore@Sun.COM /*
3759484Sgarrett.damore@Sun.COM  * Free up an OSS user land control to internal control,
3769484Sgarrett.damore@Sun.COM  * helper table.
3779484Sgarrett.damore@Sun.COM  */
3789484Sgarrett.damore@Sun.COM static void
oss_free_controls(ossdev_t * odev)3799484Sgarrett.damore@Sun.COM oss_free_controls(ossdev_t *odev)
3809484Sgarrett.damore@Sun.COM {
3819484Sgarrett.damore@Sun.COM 	kmem_free(odev->d_ctrls, sizeof (audio_ctrl_t *) * odev->d_nalloc);
3829484Sgarrett.damore@Sun.COM 	kmem_free(odev->d_exts, sizeof (oss_mixext) * odev->d_nalloc);
3839484Sgarrett.damore@Sun.COM 	odev->d_nctrl = 0;
3849484Sgarrett.damore@Sun.COM 	odev->d_nalloc = 0;
3859484Sgarrett.damore@Sun.COM }
3869484Sgarrett.damore@Sun.COM 
3879484Sgarrett.damore@Sun.COM /*
3889484Sgarrett.damore@Sun.COM  * Allocate and fill in an OSS user land controls to internal controls
3899484Sgarrett.damore@Sun.COM  * helper table. This is done on one audio_dev device.
3909484Sgarrett.damore@Sun.COM  */
3919484Sgarrett.damore@Sun.COM static void
oss_alloc_controls(ossdev_t * odev)3929484Sgarrett.damore@Sun.COM oss_alloc_controls(ossdev_t *odev)
3939484Sgarrett.damore@Sun.COM {
3949484Sgarrett.damore@Sun.COM 	audio_dev_t		*d = odev->d_dev;
3959484Sgarrett.damore@Sun.COM 	int			nctrl = 0;
3969484Sgarrett.damore@Sun.COM 	oss_mixext		*ext;
3979484Sgarrett.damore@Sun.COM 	oss_mixext_root		*root_data;
3989484Sgarrett.damore@Sun.COM 
3999484Sgarrett.damore@Sun.COM 	/* Find out who many entries we need */
4009484Sgarrett.damore@Sun.COM 	auclnt_walk_controls(d, oss_cnt_controls, &nctrl);
4019484Sgarrett.damore@Sun.COM 	nctrl++;		/* Needs space for the device root node */
4029484Sgarrett.damore@Sun.COM 	nctrl++;		/* Needs space for the device ext marker */
4039484Sgarrett.damore@Sun.COM 	nctrl++;		/* Needs space for the play group */
4049484Sgarrett.damore@Sun.COM 	nctrl++;		/* Needs space for the record group */
4059484Sgarrett.damore@Sun.COM 	nctrl++;		/* Needs space for the monitor group */
4069484Sgarrett.damore@Sun.COM 	nctrl++;		/* Needs space for the tone group */
4079484Sgarrett.damore@Sun.COM 	nctrl++;		/* Needs space for the 3D group */
4089484Sgarrett.damore@Sun.COM 	nctrl++;		/* Needs space for the misc group */
4099484Sgarrett.damore@Sun.COM 
4109484Sgarrett.damore@Sun.COM 	/* Allocate the OSS to boomer helper table */
4119484Sgarrett.damore@Sun.COM 	odev->d_nalloc = nctrl;
4129484Sgarrett.damore@Sun.COM 	odev->d_ctrls = kmem_zalloc(sizeof (audio_ctrl_t *) * nctrl, KM_SLEEP);
4139484Sgarrett.damore@Sun.COM 	odev->d_exts = kmem_zalloc(sizeof (oss_mixext) * nctrl, KM_SLEEP);
4149484Sgarrett.damore@Sun.COM 
4159484Sgarrett.damore@Sun.COM 	/*
4169484Sgarrett.damore@Sun.COM 	 * Setup special case outputs to output OSS routes helper tables
4179484Sgarrett.damore@Sun.COM 	 */
4189484Sgarrett.damore@Sun.COM 
4199484Sgarrett.damore@Sun.COM 	/*
4209484Sgarrett.damore@Sun.COM 	 * Root node is first, that way all others parent is this one
4219484Sgarrett.damore@Sun.COM 	 */
4229484Sgarrett.damore@Sun.COM 	ext = &odev->d_exts[odev->d_nctrl];
4239484Sgarrett.damore@Sun.COM 	ext->ctrl = 0;
4249484Sgarrett.damore@Sun.COM 	ext->parent = -1;
4259484Sgarrett.damore@Sun.COM 	ext->type = MIXT_DEVROOT;
4269484Sgarrett.damore@Sun.COM 	ext->timestamp = gethrtime();
4279484Sgarrett.damore@Sun.COM 	(void) snprintf(ext->id, sizeof (ext->id), "DEVROOT");
4289484Sgarrett.damore@Sun.COM 	/*
4299484Sgarrett.damore@Sun.COM 	 * Root data... nobody should be using this though.
4309484Sgarrett.damore@Sun.COM 	 */
4319484Sgarrett.damore@Sun.COM 	root_data = (oss_mixext_root *)&ext->data;
4329484Sgarrett.damore@Sun.COM 	(void) snprintf(root_data->name, sizeof (root_data->name), "%s",
4339484Sgarrett.damore@Sun.COM 	    auclnt_get_dev_name(d));
4349484Sgarrett.damore@Sun.COM 	(void) snprintf(root_data->id, sizeof (root_data->id), "%s",
4359484Sgarrett.damore@Sun.COM 	    auclnt_get_dev_name(d));
4369484Sgarrett.damore@Sun.COM 
4379484Sgarrett.damore@Sun.COM 	odev->d_nctrl++;
4389484Sgarrett.damore@Sun.COM 
4399484Sgarrett.damore@Sun.COM 	/*
4409484Sgarrett.damore@Sun.COM 	 * Insert an extra marker -- needed to keep layout apps hapy.
4419484Sgarrett.damore@Sun.COM 	 * This prevents some apps from assuming we are in "LEGACY" mode.
4429484Sgarrett.damore@Sun.COM 	 */
4439484Sgarrett.damore@Sun.COM 	ext = &odev->d_exts[odev->d_nctrl];
4449484Sgarrett.damore@Sun.COM 	ext->ctrl = odev->d_nctrl;
4459484Sgarrett.damore@Sun.COM 	ext->control_no = -1;
4469484Sgarrett.damore@Sun.COM 	ext->type = MIXT_MARKER;
4479484Sgarrett.damore@Sun.COM 	ext->timestamp = gethrtime();
4489484Sgarrett.damore@Sun.COM 	ext->parent = 0;
4499484Sgarrett.damore@Sun.COM 	odev->d_nctrl++;
4509484Sgarrett.damore@Sun.COM 
4519484Sgarrett.damore@Sun.COM 	/* Fill in the complete table now */
4529484Sgarrett.damore@Sun.COM 	auclnt_walk_controls(d, oss_add_control, odev);
4539484Sgarrett.damore@Sun.COM 
4549484Sgarrett.damore@Sun.COM 	/* Update the update_counter reference counter for groups */
4559484Sgarrett.damore@Sun.COM 	for (nctrl = 0; nctrl < odev->d_nctrl; nctrl++) {
4569484Sgarrett.damore@Sun.COM 		int i;
4579484Sgarrett.damore@Sun.COM 
4589484Sgarrett.damore@Sun.COM 		ext = &odev->d_exts[nctrl];
4599484Sgarrett.damore@Sun.COM 		i = ext->parent;
4609484Sgarrett.damore@Sun.COM 		while ((i >= 0) && (i < odev->d_nctrl)) {
4619484Sgarrett.damore@Sun.COM 
4629484Sgarrett.damore@Sun.COM 			ext = &odev->d_exts[i];
4639484Sgarrett.damore@Sun.COM 			ASSERT(ext->parent < i);
4649484Sgarrett.damore@Sun.COM 			ASSERT((ext->type == MIXT_GROUP) ||
4659484Sgarrett.damore@Sun.COM 			    (ext->type == MIXT_DEVROOT));
4669484Sgarrett.damore@Sun.COM 			ext->update_counter++;
4679484Sgarrett.damore@Sun.COM 			i = ext->parent;
4689484Sgarrett.damore@Sun.COM 		}
4699484Sgarrett.damore@Sun.COM 	}
4709484Sgarrett.damore@Sun.COM 
4719484Sgarrett.damore@Sun.COM 	ASSERT(odev->d_nctrl <= odev->d_nalloc);
4729484Sgarrett.damore@Sun.COM }
4739484Sgarrett.damore@Sun.COM 
4749484Sgarrett.damore@Sun.COM static int
oss_open(audio_client_t * c,int oflag)4759484Sgarrett.damore@Sun.COM oss_open(audio_client_t *c, int oflag)
4769484Sgarrett.damore@Sun.COM {
4779484Sgarrett.damore@Sun.COM 	int		rv;
4789484Sgarrett.damore@Sun.COM 	ossdev_t	*odev;
4799484Sgarrett.damore@Sun.COM 	ossclient_t	*sc;
4809484Sgarrett.damore@Sun.COM 	audio_stream_t	*isp, *osp;
4819484Sgarrett.damore@Sun.COM 
4829484Sgarrett.damore@Sun.COM 	isp = auclnt_input_stream(c);
4839484Sgarrett.damore@Sun.COM 	osp = auclnt_output_stream(c);
4849484Sgarrett.damore@Sun.COM 
4859484Sgarrett.damore@Sun.COM 	/* note that OSS always uses nonblocking open() semantics */
486*12165Sgdamore@opensolaris.org 	if ((rv = auclnt_open(c, oflag | FNDELAY)) != 0) {
4879484Sgarrett.damore@Sun.COM 		return (rv);
4889484Sgarrett.damore@Sun.COM 	}
4899484Sgarrett.damore@Sun.COM 
4909484Sgarrett.damore@Sun.COM 	if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) {
4919484Sgarrett.damore@Sun.COM 		auclnt_close(c);
4929484Sgarrett.damore@Sun.COM 		return (ENOMEM);
4939484Sgarrett.damore@Sun.COM 	}
4949484Sgarrett.damore@Sun.COM 	auclnt_set_private(c, sc);
4959484Sgarrett.damore@Sun.COM 
4969484Sgarrett.damore@Sun.COM 	odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP);
4979484Sgarrett.damore@Sun.COM 
4989484Sgarrett.damore@Sun.COM 	/* set a couple of common fields */
4999484Sgarrett.damore@Sun.COM 	sc->o_client = c;
5009484Sgarrett.damore@Sun.COM 	sc->o_ossdev = odev;
5019484Sgarrett.damore@Sun.COM 
5029484Sgarrett.damore@Sun.COM 	/* set all default parameters */
5039484Sgarrett.damore@Sun.COM 	if (oflag & FWRITE) {
5049484Sgarrett.damore@Sun.COM 		if (((rv = auclnt_set_format(osp, OSS_FMT)) != 0) ||
5059484Sgarrett.damore@Sun.COM 		    ((rv = auclnt_set_rate(osp, OSS_RATE)) != 0) ||
5069484Sgarrett.damore@Sun.COM 		    ((rv = auclnt_set_channels(osp, OSS_CHANNELS)) != 0)) {
5079484Sgarrett.damore@Sun.COM 			goto failed;
5089484Sgarrett.damore@Sun.COM 		}
5099558Sgdamore@opensolaris.org 		/* default to 5 fragments to provide reasonable latency */
5109558Sgdamore@opensolaris.org 		auclnt_set_latency(osp, 5, 0);
5119484Sgarrett.damore@Sun.COM 	}
5129484Sgarrett.damore@Sun.COM 
5139484Sgarrett.damore@Sun.COM 	if (oflag & FREAD) {
5149484Sgarrett.damore@Sun.COM 		if (((rv = auclnt_set_format(isp, OSS_FMT)) != 0) ||
5159484Sgarrett.damore@Sun.COM 		    ((rv = auclnt_set_rate(isp, OSS_RATE)) != 0) ||
5169484Sgarrett.damore@Sun.COM 		    ((rv = auclnt_set_channels(isp, OSS_CHANNELS)) != 0)) {
5179484Sgarrett.damore@Sun.COM 			goto failed;
5189484Sgarrett.damore@Sun.COM 		}
5199558Sgdamore@opensolaris.org 		/* default to 5 fragments to provide reasonable latency */
5209558Sgdamore@opensolaris.org 		auclnt_set_latency(isp, 5, 0);
5219484Sgarrett.damore@Sun.COM 	}
5229484Sgarrett.damore@Sun.COM 
5239484Sgarrett.damore@Sun.COM 	return (0);
5249484Sgarrett.damore@Sun.COM 
5259484Sgarrett.damore@Sun.COM failed:
5269484Sgarrett.damore@Sun.COM 	auclnt_close(c);
5279484Sgarrett.damore@Sun.COM 	return (rv);
5289484Sgarrett.damore@Sun.COM }
5299484Sgarrett.damore@Sun.COM 
5309484Sgarrett.damore@Sun.COM static void
oss_close(audio_client_t * c)5319484Sgarrett.damore@Sun.COM oss_close(audio_client_t *c)
5329484Sgarrett.damore@Sun.COM {
5339484Sgarrett.damore@Sun.COM 	ossclient_t	*sc;
5349484Sgarrett.damore@Sun.COM 
5359484Sgarrett.damore@Sun.COM 	sc = auclnt_get_private(c);
5369484Sgarrett.damore@Sun.COM 
5379484Sgarrett.damore@Sun.COM 	if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) {
5389484Sgarrett.damore@Sun.COM 		(void) auclnt_drain(c);
5399484Sgarrett.damore@Sun.COM 	}
5409484Sgarrett.damore@Sun.COM 
5419484Sgarrett.damore@Sun.COM 	kmem_free(sc, sizeof (*sc));
5429484Sgarrett.damore@Sun.COM 
5439484Sgarrett.damore@Sun.COM 	auclnt_close(c);
5449484Sgarrett.damore@Sun.COM }
5459484Sgarrett.damore@Sun.COM 
5469484Sgarrett.damore@Sun.COM /*
5479484Sgarrett.damore@Sun.COM  * This is used to generate an array of names for an enumeration
5489484Sgarrett.damore@Sun.COM  */
5499484Sgarrett.damore@Sun.COM static ushort_t
oss_set_enum(oss_mixer_enuminfo * ei,ushort_t nxt,const char * name)5509484Sgarrett.damore@Sun.COM oss_set_enum(oss_mixer_enuminfo *ei, ushort_t nxt, const char *name)
5519484Sgarrett.damore@Sun.COM {
5529484Sgarrett.damore@Sun.COM 	uint32_t	n;
5539484Sgarrett.damore@Sun.COM 
5549484Sgarrett.damore@Sun.COM 	/* Get current entry to fill in */
5559484Sgarrett.damore@Sun.COM 	n = ei->nvalues;
5569484Sgarrett.damore@Sun.COM 	(void) snprintf(&ei->strings[nxt], ((sizeof (ei->strings) - nxt) - 1),
5579484Sgarrett.damore@Sun.COM 	    "%s", name);
5589484Sgarrett.damore@Sun.COM 	ei->strindex[n] = nxt;
5599484Sgarrett.damore@Sun.COM 
5609484Sgarrett.damore@Sun.COM 	/* Adjust everything for next entry */
5619484Sgarrett.damore@Sun.COM 	nxt += strnlen(name, ((sizeof (ei->strings) - nxt) - 1));
5629484Sgarrett.damore@Sun.COM 	ei->strings[nxt++] = '\0';
5639484Sgarrett.damore@Sun.COM 
5649484Sgarrett.damore@Sun.COM 	ei->nvalues++;
5659484Sgarrett.damore@Sun.COM 	return (nxt);
5669484Sgarrett.damore@Sun.COM }
5679484Sgarrett.damore@Sun.COM 
5689484Sgarrett.damore@Sun.COM /*
5699484Sgarrett.damore@Sun.COM  * The following two functions are used to count the number of devices
5709484Sgarrett.damore@Sun.COM  * in under the boomer framework.
5719484Sgarrett.damore@Sun.COM  *
5729484Sgarrett.damore@Sun.COM  * We actually report the highest "index", and then if an audio device
5739484Sgarrett.damore@Sun.COM  * is not found, we report a bogus removed device for it in the actual
5749484Sgarrett.damore@Sun.COM  * ioctls.  This goofiness is required to make the OSS API happy.
5759484Sgarrett.damore@Sun.COM  */
5769484Sgarrett.damore@Sun.COM int
oss_dev_walker(audio_dev_t * d,void * arg)5779484Sgarrett.damore@Sun.COM oss_dev_walker(audio_dev_t *d, void *arg)
5789484Sgarrett.damore@Sun.COM {
5799484Sgarrett.damore@Sun.COM 	int		*pcnt = arg;
5809484Sgarrett.damore@Sun.COM 	int		cnt;
5819484Sgarrett.damore@Sun.COM 	int		index;
5829484Sgarrett.damore@Sun.COM 
5839484Sgarrett.damore@Sun.COM 	cnt = *pcnt;
5849484Sgarrett.damore@Sun.COM 	index = auclnt_get_dev_index(d);
5859484Sgarrett.damore@Sun.COM 	if ((index + 1) > cnt) {
5869484Sgarrett.damore@Sun.COM 		cnt = index + 1;
5879484Sgarrett.damore@Sun.COM 		*pcnt = cnt;
5889484Sgarrett.damore@Sun.COM 	}
5899484Sgarrett.damore@Sun.COM 
5909484Sgarrett.damore@Sun.COM 	return (AUDIO_WALK_CONTINUE);
5919484Sgarrett.damore@Sun.COM }
5929484Sgarrett.damore@Sun.COM 
5939484Sgarrett.damore@Sun.COM static int
oss_cnt_devs(void)5949484Sgarrett.damore@Sun.COM oss_cnt_devs(void)
5959484Sgarrett.damore@Sun.COM {
5969484Sgarrett.damore@Sun.COM 	int cnt = 0;
5979484Sgarrett.damore@Sun.COM 
5989484Sgarrett.damore@Sun.COM 	auclnt_walk_devs(oss_dev_walker, &cnt);
5999484Sgarrett.damore@Sun.COM 	return (cnt);
6009484Sgarrett.damore@Sun.COM }
6019484Sgarrett.damore@Sun.COM 
6029484Sgarrett.damore@Sun.COM static int
sndctl_dsp_speed(audio_client_t * c,int * ratep)6039484Sgarrett.damore@Sun.COM sndctl_dsp_speed(audio_client_t *c, int *ratep)
6049484Sgarrett.damore@Sun.COM {
6059484Sgarrett.damore@Sun.COM 	int		rate;
6069484Sgarrett.damore@Sun.COM 	int		oflag;
6079484Sgarrett.damore@Sun.COM 
6089484Sgarrett.damore@Sun.COM 	rate = *ratep;
6099484Sgarrett.damore@Sun.COM 
6109484Sgarrett.damore@Sun.COM 	oflag = auclnt_get_oflag(c);
6119484Sgarrett.damore@Sun.COM 	if (oflag & FREAD) {
61210477SGarrett.Damore@Sun.COM 		(void) auclnt_set_rate(auclnt_input_stream(c), rate);
61310477SGarrett.Damore@Sun.COM 		*ratep = auclnt_get_rate(auclnt_input_stream(c));
6149484Sgarrett.damore@Sun.COM 	}
6159484Sgarrett.damore@Sun.COM 
6169484Sgarrett.damore@Sun.COM 	if (oflag & FWRITE) {
61710477SGarrett.Damore@Sun.COM 		(void) auclnt_set_rate(auclnt_output_stream(c), rate);
61810477SGarrett.Damore@Sun.COM 		*ratep = auclnt_get_rate(auclnt_output_stream(c));
6199484Sgarrett.damore@Sun.COM 	}
6209484Sgarrett.damore@Sun.COM 
6219484Sgarrett.damore@Sun.COM 	return (0);
6229484Sgarrett.damore@Sun.COM }
6239484Sgarrett.damore@Sun.COM 
6249484Sgarrett.damore@Sun.COM static int
sndctl_dsp_setfmt(audio_client_t * c,int * fmtp)6259484Sgarrett.damore@Sun.COM sndctl_dsp_setfmt(audio_client_t *c, int *fmtp)
6269484Sgarrett.damore@Sun.COM {
6279484Sgarrett.damore@Sun.COM 	int		fmt;
6289484Sgarrett.damore@Sun.COM 	int		i;
6299484Sgarrett.damore@Sun.COM 	int		oflag;
6309484Sgarrett.damore@Sun.COM 
6319484Sgarrett.damore@Sun.COM 	oflag = auclnt_get_oflag(c);
6329484Sgarrett.damore@Sun.COM 
6339484Sgarrett.damore@Sun.COM 	if (*fmtp != AFMT_QUERY) {
6349484Sgarrett.damore@Sun.COM 		/* convert from OSS */
6359484Sgarrett.damore@Sun.COM 		for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) {
6369484Sgarrett.damore@Sun.COM 			if (oss_formats[i].oss == *fmtp) {
6379484Sgarrett.damore@Sun.COM 				fmt = oss_formats[i].fmt;
6389484Sgarrett.damore@Sun.COM 				break;
6399484Sgarrett.damore@Sun.COM 			}
6409484Sgarrett.damore@Sun.COM 		}
6419484Sgarrett.damore@Sun.COM 		if (fmt == AUDIO_FORMAT_NONE) {
64210477SGarrett.Damore@Sun.COM 			/* if format not known, return */
64310477SGarrett.Damore@Sun.COM 			goto done;
6449484Sgarrett.damore@Sun.COM 		}
6459484Sgarrett.damore@Sun.COM 
6469484Sgarrett.damore@Sun.COM 		if (oflag & FWRITE) {
64710477SGarrett.Damore@Sun.COM 			(void) auclnt_set_format(auclnt_output_stream(c), fmt);
6489484Sgarrett.damore@Sun.COM 		}
6499484Sgarrett.damore@Sun.COM 
6509484Sgarrett.damore@Sun.COM 		if (oflag & FREAD) {
65110477SGarrett.Damore@Sun.COM 			(void) auclnt_set_format(auclnt_input_stream(c), fmt);
6529484Sgarrett.damore@Sun.COM 		}
6539484Sgarrett.damore@Sun.COM 	}
6549484Sgarrett.damore@Sun.COM 
65510477SGarrett.Damore@Sun.COM done:
6569484Sgarrett.damore@Sun.COM 	if (oflag & FWRITE) {
6579484Sgarrett.damore@Sun.COM 		fmt = auclnt_get_format(auclnt_output_stream(c));
6589484Sgarrett.damore@Sun.COM 	} else if (oflag & FREAD) {
6599484Sgarrett.damore@Sun.COM 		fmt = auclnt_get_format(auclnt_input_stream(c));
6609484Sgarrett.damore@Sun.COM 	}
6619484Sgarrett.damore@Sun.COM 
6629484Sgarrett.damore@Sun.COM 	/* convert back to OSS */
6639484Sgarrett.damore@Sun.COM 	*(int *)fmtp = AFMT_QUERY;
6649484Sgarrett.damore@Sun.COM 	for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) {
6659484Sgarrett.damore@Sun.COM 		if (oss_formats[i].fmt == fmt) {
6669484Sgarrett.damore@Sun.COM 			*(int *)fmtp = oss_formats[i].oss;
6679484Sgarrett.damore@Sun.COM 		}
6689484Sgarrett.damore@Sun.COM 	}
6699484Sgarrett.damore@Sun.COM 
6709484Sgarrett.damore@Sun.COM 	return (0);
6719484Sgarrett.damore@Sun.COM }
6729484Sgarrett.damore@Sun.COM 
6739484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getfmts(audio_client_t * c,int * fmtsp)6749484Sgarrett.damore@Sun.COM sndctl_dsp_getfmts(audio_client_t *c, int *fmtsp)
6759484Sgarrett.damore@Sun.COM {
6769484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
6779484Sgarrett.damore@Sun.COM 
6789484Sgarrett.damore@Sun.COM 	/*
6799484Sgarrett.damore@Sun.COM 	 * For now, we support all the standard ones.  Later we might
6809484Sgarrett.damore@Sun.COM 	 * add in conditional support for AC3.
6819484Sgarrett.damore@Sun.COM 	 */
6829484Sgarrett.damore@Sun.COM 	*fmtsp = (AFMT_MU_LAW | AFMT_A_LAW |
6839484Sgarrett.damore@Sun.COM 	    AFMT_U8 | AFMT_S8 |
6849484Sgarrett.damore@Sun.COM 	    AFMT_S16_LE |AFMT_S16_BE |
6859484Sgarrett.damore@Sun.COM 	    AFMT_S24_LE | AFMT_S24_BE |
6869484Sgarrett.damore@Sun.COM 	    AFMT_S32_LE | AFMT_S32_BE |
6879484Sgarrett.damore@Sun.COM 	    AFMT_S24_PACKED);
6889484Sgarrett.damore@Sun.COM 
6899484Sgarrett.damore@Sun.COM 	return (0);
6909484Sgarrett.damore@Sun.COM }
6919484Sgarrett.damore@Sun.COM 
6929484Sgarrett.damore@Sun.COM static int
sndctl_dsp_channels(audio_client_t * c,int * chanp)6939484Sgarrett.damore@Sun.COM sndctl_dsp_channels(audio_client_t *c, int *chanp)
6949484Sgarrett.damore@Sun.COM {
6959484Sgarrett.damore@Sun.COM 	int		nchan;
6969484Sgarrett.damore@Sun.COM 	int		oflag;
6979484Sgarrett.damore@Sun.COM 
6989484Sgarrett.damore@Sun.COM 	oflag = auclnt_get_oflag(c);
6999484Sgarrett.damore@Sun.COM 
7009484Sgarrett.damore@Sun.COM 	nchan = *chanp;
7019484Sgarrett.damore@Sun.COM 	if (nchan != 0) {
7029484Sgarrett.damore@Sun.COM 		if (oflag & FWRITE) {
70310477SGarrett.Damore@Sun.COM 			(void) auclnt_set_channels(auclnt_output_stream(c),
7049484Sgarrett.damore@Sun.COM 			    nchan);
7059484Sgarrett.damore@Sun.COM 		}
7069484Sgarrett.damore@Sun.COM 
7079484Sgarrett.damore@Sun.COM 		if (oflag & FREAD) {
70810477SGarrett.Damore@Sun.COM 			(void) auclnt_set_channels(auclnt_input_stream(c),
70910477SGarrett.Damore@Sun.COM 			    nchan);
7109484Sgarrett.damore@Sun.COM 		}
7119484Sgarrett.damore@Sun.COM 	}
7129484Sgarrett.damore@Sun.COM 
7139484Sgarrett.damore@Sun.COM 	if (oflag & FWRITE) {
7149484Sgarrett.damore@Sun.COM 		nchan = auclnt_get_channels(auclnt_output_stream(c));
7159484Sgarrett.damore@Sun.COM 	} else if (oflag & FREAD) {
7169484Sgarrett.damore@Sun.COM 		nchan = auclnt_get_channels(auclnt_input_stream(c));
7179484Sgarrett.damore@Sun.COM 	}
7189484Sgarrett.damore@Sun.COM 	*chanp = nchan;
7199484Sgarrett.damore@Sun.COM 	return (0);
7209484Sgarrett.damore@Sun.COM }
7219484Sgarrett.damore@Sun.COM 
7229484Sgarrett.damore@Sun.COM static int
sndctl_dsp_stereo(audio_client_t * c,int * onoff)7239484Sgarrett.damore@Sun.COM sndctl_dsp_stereo(audio_client_t *c, int *onoff)
7249484Sgarrett.damore@Sun.COM {
7259484Sgarrett.damore@Sun.COM 	int	nchan;
7269484Sgarrett.damore@Sun.COM 
7279484Sgarrett.damore@Sun.COM 	switch (*onoff) {
7289484Sgarrett.damore@Sun.COM 	case 0:
7299484Sgarrett.damore@Sun.COM 		nchan = 1;
7309484Sgarrett.damore@Sun.COM 		break;
7319484Sgarrett.damore@Sun.COM 	case 1:
7329484Sgarrett.damore@Sun.COM 		nchan = 2;
7339484Sgarrett.damore@Sun.COM 		break;
7349484Sgarrett.damore@Sun.COM 	default:
7359484Sgarrett.damore@Sun.COM 		return (EINVAL);
7369484Sgarrett.damore@Sun.COM 	}
7379484Sgarrett.damore@Sun.COM 
7389484Sgarrett.damore@Sun.COM 	return (sndctl_dsp_channels(c, &nchan));
7399484Sgarrett.damore@Sun.COM }
7409484Sgarrett.damore@Sun.COM 
7419484Sgarrett.damore@Sun.COM static int
sndctl_dsp_post(audio_client_t * c)7429484Sgarrett.damore@Sun.COM sndctl_dsp_post(audio_client_t *c)
7439484Sgarrett.damore@Sun.COM {
7449484Sgarrett.damore@Sun.COM 	if (auclnt_get_oflag(c) & FWRITE) {
7459484Sgarrett.damore@Sun.COM 		audio_stream_t	*sp = auclnt_output_stream(c);
7469484Sgarrett.damore@Sun.COM 		auclnt_flush(sp);
7479484Sgarrett.damore@Sun.COM 		auclnt_clear_paused(sp);
7489484Sgarrett.damore@Sun.COM 	}
7499484Sgarrett.damore@Sun.COM 	return (0);
7509484Sgarrett.damore@Sun.COM }
7519484Sgarrett.damore@Sun.COM 
7529484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getcaps(audio_client_t * c,int * capsp)7539484Sgarrett.damore@Sun.COM sndctl_dsp_getcaps(audio_client_t *c, int *capsp)
7549484Sgarrett.damore@Sun.COM {
7559484Sgarrett.damore@Sun.COM 	int		ncaps;
7569484Sgarrett.damore@Sun.COM 	int		osscaps = 0;
7579484Sgarrett.damore@Sun.COM 
7589484Sgarrett.damore@Sun.COM 	ncaps = auclnt_get_dev_capab(auclnt_get_dev(c));
7599484Sgarrett.damore@Sun.COM 
7609484Sgarrett.damore@Sun.COM 	if (ncaps & AUDIO_CLIENT_CAP_PLAY)
7619484Sgarrett.damore@Sun.COM 		osscaps |= PCM_CAP_OUTPUT;
7629484Sgarrett.damore@Sun.COM 	if (ncaps & AUDIO_CLIENT_CAP_RECORD)
7639484Sgarrett.damore@Sun.COM 		osscaps |= PCM_CAP_INPUT;
7649484Sgarrett.damore@Sun.COM 	if (ncaps & AUDIO_CLIENT_CAP_DUPLEX)
7659484Sgarrett.damore@Sun.COM 		osscaps |= PCM_CAP_DUPLEX;
7669484Sgarrett.damore@Sun.COM 
76710477SGarrett.Damore@Sun.COM 	if (osscaps != 0) {
76810477SGarrett.Damore@Sun.COM 		osscaps |= PCM_CAP_TRIGGER | PCM_CAP_BATCH;
76910477SGarrett.Damore@Sun.COM 		if (!(ncaps & AUDIO_CLIENT_CAP_OPAQUE)) {
77010477SGarrett.Damore@Sun.COM 			osscaps |= PCM_CAP_FREERATE | PCM_CAP_MULTI;
77110477SGarrett.Damore@Sun.COM 		}
77210477SGarrett.Damore@Sun.COM 	} else {
77310477SGarrett.Damore@Sun.COM 		/* This is the sndstat device! */
77410477SGarrett.Damore@Sun.COM 		osscaps = PCM_CAP_VIRTUAL;
77510477SGarrett.Damore@Sun.COM 	}
77610477SGarrett.Damore@Sun.COM 
7779484Sgarrett.damore@Sun.COM 	*capsp = osscaps;
7789484Sgarrett.damore@Sun.COM 	return (0);
7799484Sgarrett.damore@Sun.COM }
7809484Sgarrett.damore@Sun.COM 
7819484Sgarrett.damore@Sun.COM static int
sndctl_dsp_gettrigger(audio_client_t * c,int * trigp)7829484Sgarrett.damore@Sun.COM sndctl_dsp_gettrigger(audio_client_t *c, int *trigp)
7839484Sgarrett.damore@Sun.COM {
7849484Sgarrett.damore@Sun.COM 	int		triggers = 0;
7859484Sgarrett.damore@Sun.COM 	int		oflag;
7869484Sgarrett.damore@Sun.COM 
7879484Sgarrett.damore@Sun.COM 	oflag = auclnt_get_oflag(c);
7889484Sgarrett.damore@Sun.COM 
7899484Sgarrett.damore@Sun.COM 	if (oflag & FWRITE) {
7909484Sgarrett.damore@Sun.COM 		if (!auclnt_is_paused(auclnt_output_stream(c))) {
7919484Sgarrett.damore@Sun.COM 			triggers |= PCM_ENABLE_OUTPUT;
7929484Sgarrett.damore@Sun.COM 		}
7939484Sgarrett.damore@Sun.COM 	}
7949484Sgarrett.damore@Sun.COM 
7959484Sgarrett.damore@Sun.COM 	if (oflag & FREAD) {
7969484Sgarrett.damore@Sun.COM 		if (!auclnt_is_paused(auclnt_input_stream(c))) {
7979484Sgarrett.damore@Sun.COM 			triggers |= PCM_ENABLE_INPUT;
7989484Sgarrett.damore@Sun.COM 		}
7999484Sgarrett.damore@Sun.COM 	}
8009484Sgarrett.damore@Sun.COM 	*trigp = triggers;
8019484Sgarrett.damore@Sun.COM 
8029484Sgarrett.damore@Sun.COM 	return (0);
8039484Sgarrett.damore@Sun.COM }
8049484Sgarrett.damore@Sun.COM 
8059484Sgarrett.damore@Sun.COM static int
sndctl_dsp_settrigger(audio_client_t * c,int * trigp)8069484Sgarrett.damore@Sun.COM sndctl_dsp_settrigger(audio_client_t *c, int *trigp)
8079484Sgarrett.damore@Sun.COM {
8089484Sgarrett.damore@Sun.COM 	int		triggers;
8099484Sgarrett.damore@Sun.COM 	int		oflag;
8109496Sgdamore@opensolaris.org 	audio_stream_t	*sp;
8119484Sgarrett.damore@Sun.COM 
8129484Sgarrett.damore@Sun.COM 	oflag = auclnt_get_oflag(c);
8139484Sgarrett.damore@Sun.COM 	triggers = *trigp;
8149484Sgarrett.damore@Sun.COM 
8159484Sgarrett.damore@Sun.COM 	if ((oflag & FWRITE) && (triggers & PCM_ENABLE_OUTPUT)) {
8169496Sgdamore@opensolaris.org 		sp = auclnt_output_stream(c);
8179496Sgdamore@opensolaris.org 		auclnt_clear_paused(sp);
8189496Sgdamore@opensolaris.org 		auclnt_start(sp);
8199484Sgarrett.damore@Sun.COM 	}
8209484Sgarrett.damore@Sun.COM 
8219484Sgarrett.damore@Sun.COM 	if ((oflag & FREAD) && (triggers & PCM_ENABLE_INPUT)) {
8229496Sgdamore@opensolaris.org 		sp = auclnt_input_stream(c);
8239496Sgdamore@opensolaris.org 		auclnt_clear_paused(sp);
8249496Sgdamore@opensolaris.org 		auclnt_start(sp);
8259484Sgarrett.damore@Sun.COM 	}
8269484Sgarrett.damore@Sun.COM 
8279484Sgarrett.damore@Sun.COM 	return (0);
8289484Sgarrett.damore@Sun.COM }
8299484Sgarrett.damore@Sun.COM 
8309484Sgarrett.damore@Sun.COM struct oss_legacy_volume {
8319484Sgarrett.damore@Sun.COM 	pid_t		pid;
8329484Sgarrett.damore@Sun.COM 	uint8_t		ogain;
8339484Sgarrett.damore@Sun.COM 	uint8_t		igain;
8349484Sgarrett.damore@Sun.COM };
8359484Sgarrett.damore@Sun.COM 
8369484Sgarrett.damore@Sun.COM static int
oss_legacy_volume_walker(audio_client_t * c,void * arg)8379484Sgarrett.damore@Sun.COM oss_legacy_volume_walker(audio_client_t *c, void *arg)
8389484Sgarrett.damore@Sun.COM {
8399484Sgarrett.damore@Sun.COM 	struct oss_legacy_volume	 *olv = arg;
8409484Sgarrett.damore@Sun.COM 
8419484Sgarrett.damore@Sun.COM 	if (auclnt_get_pid(c) == olv->pid) {
8429484Sgarrett.damore@Sun.COM 		if (olv->ogain <= 100) {
8439484Sgarrett.damore@Sun.COM 			auclnt_set_gain(auclnt_output_stream(c), olv->ogain);
8449484Sgarrett.damore@Sun.COM 		}
8459484Sgarrett.damore@Sun.COM 		if (olv->igain <= 100) {
8469484Sgarrett.damore@Sun.COM 			auclnt_set_gain(auclnt_input_stream(c), olv->igain);
8479484Sgarrett.damore@Sun.COM 		}
8489484Sgarrett.damore@Sun.COM 	}
8499484Sgarrett.damore@Sun.COM 	return (AUDIO_WALK_CONTINUE);
8509484Sgarrett.damore@Sun.COM }
8519484Sgarrett.damore@Sun.COM 
8529484Sgarrett.damore@Sun.COM static void
oss_set_legacy_volume(audio_client_t * c,uint8_t ogain,uint8_t igain)8539484Sgarrett.damore@Sun.COM oss_set_legacy_volume(audio_client_t *c, uint8_t ogain, uint8_t igain)
8549484Sgarrett.damore@Sun.COM {
8559484Sgarrett.damore@Sun.COM 	struct oss_legacy_volume olv;
8569484Sgarrett.damore@Sun.COM 
8579484Sgarrett.damore@Sun.COM 	olv.pid = auclnt_get_pid(c);
8589484Sgarrett.damore@Sun.COM 	olv.ogain = ogain;
8599484Sgarrett.damore@Sun.COM 	olv.igain = igain;
8609484Sgarrett.damore@Sun.COM 	auclnt_dev_walk_clients(auclnt_get_dev(c),
8619484Sgarrett.damore@Sun.COM 	    oss_legacy_volume_walker, &olv);
8629484Sgarrett.damore@Sun.COM }
8639484Sgarrett.damore@Sun.COM 
8649484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getplayvol(audio_client_t * c,int * volp)8659484Sgarrett.damore@Sun.COM sndctl_dsp_getplayvol(audio_client_t *c, int *volp)
8669484Sgarrett.damore@Sun.COM {
8679484Sgarrett.damore@Sun.COM 	int	vol;
8689484Sgarrett.damore@Sun.COM 
8699484Sgarrett.damore@Sun.COM 	/* convert monophonic soft value to OSS stereo value */
8709484Sgarrett.damore@Sun.COM 	vol = auclnt_get_gain(auclnt_output_stream(c));
8719484Sgarrett.damore@Sun.COM 	*volp = vol | (vol << 8);
8729484Sgarrett.damore@Sun.COM 	return (0);
8739484Sgarrett.damore@Sun.COM }
8749484Sgarrett.damore@Sun.COM 
8759484Sgarrett.damore@Sun.COM static int
sndctl_dsp_setplayvol(audio_client_t * c,int * volp)8769484Sgarrett.damore@Sun.COM sndctl_dsp_setplayvol(audio_client_t *c, int *volp)
8779484Sgarrett.damore@Sun.COM {
8789484Sgarrett.damore@Sun.COM 	uint8_t		vol;
8799484Sgarrett.damore@Sun.COM 
8809484Sgarrett.damore@Sun.COM 	vol = *volp & 0xff;
8819484Sgarrett.damore@Sun.COM 	if (vol > 100) {
8829484Sgarrett.damore@Sun.COM 		return (EINVAL);
8839484Sgarrett.damore@Sun.COM 	}
8849484Sgarrett.damore@Sun.COM 
8859484Sgarrett.damore@Sun.COM 	auclnt_set_gain(auclnt_output_stream(c), vol);
8869484Sgarrett.damore@Sun.COM 	*volp = (vol | (vol << 8));
8879484Sgarrett.damore@Sun.COM 
8889484Sgarrett.damore@Sun.COM 	return (0);
8899484Sgarrett.damore@Sun.COM }
8909484Sgarrett.damore@Sun.COM 
8919484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getrecvol(audio_client_t * c,int * volp)8929484Sgarrett.damore@Sun.COM sndctl_dsp_getrecvol(audio_client_t *c, int *volp)
8939484Sgarrett.damore@Sun.COM {
8949484Sgarrett.damore@Sun.COM 	int	vol;
8959484Sgarrett.damore@Sun.COM 
8969484Sgarrett.damore@Sun.COM 	vol = auclnt_get_gain(auclnt_input_stream(c));
8979484Sgarrett.damore@Sun.COM 	*volp = (vol | (vol << 8));
8989484Sgarrett.damore@Sun.COM 	return (0);
8999484Sgarrett.damore@Sun.COM }
9009484Sgarrett.damore@Sun.COM 
9019484Sgarrett.damore@Sun.COM static int
sndctl_dsp_setrecvol(audio_client_t * c,int * volp)9029484Sgarrett.damore@Sun.COM sndctl_dsp_setrecvol(audio_client_t *c, int *volp)
9039484Sgarrett.damore@Sun.COM {
9049484Sgarrett.damore@Sun.COM 	uint8_t		vol;
9059484Sgarrett.damore@Sun.COM 
9069484Sgarrett.damore@Sun.COM 	vol = *volp & 0xff;
9079484Sgarrett.damore@Sun.COM 	if (vol > 100) {
9089484Sgarrett.damore@Sun.COM 		return (EINVAL);
9099484Sgarrett.damore@Sun.COM 	}
9109484Sgarrett.damore@Sun.COM 
9119484Sgarrett.damore@Sun.COM 	auclnt_set_gain(auclnt_input_stream(c), vol);
9129484Sgarrett.damore@Sun.COM 	*volp = (vol | (vol << 8));
9139484Sgarrett.damore@Sun.COM 
9149484Sgarrett.damore@Sun.COM 	return (0);
9159484Sgarrett.damore@Sun.COM }
9169484Sgarrett.damore@Sun.COM 
9179484Sgarrett.damore@Sun.COM static int
sound_mixer_write_ogain(audio_client_t * c,int * volp)9189484Sgarrett.damore@Sun.COM sound_mixer_write_ogain(audio_client_t *c, int *volp)
9199484Sgarrett.damore@Sun.COM {
9209484Sgarrett.damore@Sun.COM 	uint8_t		vol;
9219484Sgarrett.damore@Sun.COM 
9229484Sgarrett.damore@Sun.COM 	vol = *volp & 0xff;
9239484Sgarrett.damore@Sun.COM 	if (vol > 100) {
9249484Sgarrett.damore@Sun.COM 		return (EINVAL);
9259484Sgarrett.damore@Sun.COM 	}
9269484Sgarrett.damore@Sun.COM 	oss_set_legacy_volume(c, vol, 255);
9279484Sgarrett.damore@Sun.COM 	*volp = (vol | (vol << 8));
9289484Sgarrett.damore@Sun.COM 	return (0);
9299484Sgarrett.damore@Sun.COM }
9309484Sgarrett.damore@Sun.COM 
9319484Sgarrett.damore@Sun.COM static int
sound_mixer_write_igain(audio_client_t * c,int * volp)9329484Sgarrett.damore@Sun.COM sound_mixer_write_igain(audio_client_t *c, int *volp)
9339484Sgarrett.damore@Sun.COM {
9349484Sgarrett.damore@Sun.COM 	uint8_t		vol;
9359484Sgarrett.damore@Sun.COM 
9369484Sgarrett.damore@Sun.COM 	vol = *volp & 0xff;
9379484Sgarrett.damore@Sun.COM 	if (vol > 100) {
9389484Sgarrett.damore@Sun.COM 		return (EINVAL);
9399484Sgarrett.damore@Sun.COM 	}
9409484Sgarrett.damore@Sun.COM 	oss_set_legacy_volume(c, 255, vol);
9419484Sgarrett.damore@Sun.COM 	*volp = (vol | (vol << 8));
9429484Sgarrett.damore@Sun.COM 	return (0);
9439484Sgarrett.damore@Sun.COM }
9449484Sgarrett.damore@Sun.COM 
9459484Sgarrett.damore@Sun.COM static int
sndctl_dsp_readctl(audio_client_t * c,oss_digital_control * ctl)9469484Sgarrett.damore@Sun.COM sndctl_dsp_readctl(audio_client_t *c, oss_digital_control *ctl)
9479484Sgarrett.damore@Sun.COM {
9489484Sgarrett.damore@Sun.COM 	/* SPDIF: need to add support with spdif */
9499484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
9509484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(ctl));
9519484Sgarrett.damore@Sun.COM 	return (ENOTSUP);
9529484Sgarrett.damore@Sun.COM }
9539484Sgarrett.damore@Sun.COM 
9549484Sgarrett.damore@Sun.COM static int
sndctl_dsp_writectl(audio_client_t * c,oss_digital_control * ctl)9559484Sgarrett.damore@Sun.COM sndctl_dsp_writectl(audio_client_t *c, oss_digital_control *ctl)
9569484Sgarrett.damore@Sun.COM {
9579484Sgarrett.damore@Sun.COM 	/* SPDIF: need to add support with spdif */
9589484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
9599484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(ctl));
9609484Sgarrett.damore@Sun.COM 	return (ENOTSUP);
9619484Sgarrett.damore@Sun.COM }
9629484Sgarrett.damore@Sun.COM 
9639484Sgarrett.damore@Sun.COM static int
sndctl_dsp_cookedmode(audio_client_t * c,int * rvp)9649484Sgarrett.damore@Sun.COM sndctl_dsp_cookedmode(audio_client_t *c, int *rvp)
9659484Sgarrett.damore@Sun.COM {
9669484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
9679484Sgarrett.damore@Sun.COM 
9689484Sgarrett.damore@Sun.COM 	/* We are *always* in cooked mode -- at least until we have AC3. */
9699484Sgarrett.damore@Sun.COM 	if (*rvp == 0) {
9709484Sgarrett.damore@Sun.COM 		return (ENOTSUP);
9719484Sgarrett.damore@Sun.COM 	} else {
9729484Sgarrett.damore@Sun.COM 		return (0);
9739484Sgarrett.damore@Sun.COM 	}
9749484Sgarrett.damore@Sun.COM }
9759484Sgarrett.damore@Sun.COM 
9769484Sgarrett.damore@Sun.COM static int
sndctl_dsp_silence(audio_client_t * c)9779484Sgarrett.damore@Sun.COM sndctl_dsp_silence(audio_client_t *c)
9789484Sgarrett.damore@Sun.COM {
9799484Sgarrett.damore@Sun.COM 	if (auclnt_get_oflag(c) & FWRITE) {
9809484Sgarrett.damore@Sun.COM 		audio_stream_t	*sp = auclnt_output_stream(c);
9819484Sgarrett.damore@Sun.COM 		auclnt_set_paused(sp);
9829484Sgarrett.damore@Sun.COM 		auclnt_flush(sp);
9839484Sgarrett.damore@Sun.COM 	}
9849484Sgarrett.damore@Sun.COM 	return (0);
9859484Sgarrett.damore@Sun.COM }
9869484Sgarrett.damore@Sun.COM 
9879484Sgarrett.damore@Sun.COM static int
sndctl_dsp_skip(audio_client_t * c)9889484Sgarrett.damore@Sun.COM sndctl_dsp_skip(audio_client_t *c)
9899484Sgarrett.damore@Sun.COM {
9909484Sgarrett.damore@Sun.COM 	if (auclnt_get_oflag(c) & FWRITE) {
9919484Sgarrett.damore@Sun.COM 		audio_stream_t	*sp = auclnt_output_stream(c);
9929484Sgarrett.damore@Sun.COM 		auclnt_set_paused(sp);
9939484Sgarrett.damore@Sun.COM 		auclnt_flush(sp);
9949484Sgarrett.damore@Sun.COM 		auclnt_clear_paused(sp);
9959484Sgarrett.damore@Sun.COM 	}
9969484Sgarrett.damore@Sun.COM 	return (0);
9979484Sgarrett.damore@Sun.COM }
9989484Sgarrett.damore@Sun.COM 
9999484Sgarrett.damore@Sun.COM static int
sndctl_dsp_halt_input(audio_client_t * c)10009484Sgarrett.damore@Sun.COM sndctl_dsp_halt_input(audio_client_t *c)
10019484Sgarrett.damore@Sun.COM {
10029484Sgarrett.damore@Sun.COM 	if (auclnt_get_oflag(c) & FREAD) {
10039484Sgarrett.damore@Sun.COM 		audio_stream_t	*sp = auclnt_input_stream(c);
10049484Sgarrett.damore@Sun.COM 		auclnt_set_paused(sp);
10059484Sgarrett.damore@Sun.COM 		auclnt_flush(sp);
10069484Sgarrett.damore@Sun.COM 	}
10079484Sgarrett.damore@Sun.COM 	return (0);
10089484Sgarrett.damore@Sun.COM }
10099484Sgarrett.damore@Sun.COM 
10109484Sgarrett.damore@Sun.COM static int
sndctl_dsp_halt_output(audio_client_t * c)10119484Sgarrett.damore@Sun.COM sndctl_dsp_halt_output(audio_client_t *c)
10129484Sgarrett.damore@Sun.COM {
10139484Sgarrett.damore@Sun.COM 	if (auclnt_get_oflag(c) & FWRITE) {
10149484Sgarrett.damore@Sun.COM 		audio_stream_t	*sp = auclnt_output_stream(c);
10159484Sgarrett.damore@Sun.COM 		auclnt_set_paused(sp);
10169484Sgarrett.damore@Sun.COM 		auclnt_flush(sp);
10179484Sgarrett.damore@Sun.COM 	}
10189484Sgarrett.damore@Sun.COM 	return (0);
10199484Sgarrett.damore@Sun.COM }
10209484Sgarrett.damore@Sun.COM 
10219484Sgarrett.damore@Sun.COM static int
sndctl_dsp_halt(audio_client_t * c)10229484Sgarrett.damore@Sun.COM sndctl_dsp_halt(audio_client_t *c)
10239484Sgarrett.damore@Sun.COM {
10249484Sgarrett.damore@Sun.COM 	(void) sndctl_dsp_halt_input(c);
10259484Sgarrett.damore@Sun.COM 	(void) sndctl_dsp_halt_output(c);
10269484Sgarrett.damore@Sun.COM 	return (0);
10279484Sgarrett.damore@Sun.COM }
10289484Sgarrett.damore@Sun.COM 
10299484Sgarrett.damore@Sun.COM static int
sndctl_dsp_sync(audio_client_t * c)10309484Sgarrett.damore@Sun.COM sndctl_dsp_sync(audio_client_t *c)
10319484Sgarrett.damore@Sun.COM {
10329484Sgarrett.damore@Sun.COM 	return (auclnt_drain(c));
10339484Sgarrett.damore@Sun.COM }
10349484Sgarrett.damore@Sun.COM 
10359484Sgarrett.damore@Sun.COM static int
sndctl_dsp_setfragment(audio_client_t * c,int * fragp)10369484Sgarrett.damore@Sun.COM sndctl_dsp_setfragment(audio_client_t *c, int *fragp)
10379484Sgarrett.damore@Sun.COM {
10389558Sgdamore@opensolaris.org 	int	bufsz;
10399558Sgdamore@opensolaris.org 	int	nfrags;
10409558Sgdamore@opensolaris.org 	int	fragsz;
10419558Sgdamore@opensolaris.org 
10429558Sgdamore@opensolaris.org 	nfrags = (*fragp) >> 16;
10439558Sgdamore@opensolaris.org 	if ((nfrags >= 0x7fffU) || (nfrags < 2)) {
10449558Sgdamore@opensolaris.org 		/* use infinite setting... no change */
10459558Sgdamore@opensolaris.org 		return (0);
10469558Sgdamore@opensolaris.org 	}
10479558Sgdamore@opensolaris.org 
10489558Sgdamore@opensolaris.org 	fragsz = (*fragp) & 0xffff;
10499558Sgdamore@opensolaris.org 	if (fragsz > 16) {
10509558Sgdamore@opensolaris.org 		/* basically too big, so, no change */
10519558Sgdamore@opensolaris.org 		return (0);
10529558Sgdamore@opensolaris.org 	}
10539558Sgdamore@opensolaris.org 	bufsz = (1U << fragsz) * nfrags;
10549558Sgdamore@opensolaris.org 
10559484Sgarrett.damore@Sun.COM 	/*
10569558Sgdamore@opensolaris.org 	 * Now we have our desired buffer size, but we have to
10579558Sgdamore@opensolaris.org 	 * make sure we have a whole number of fragments >= 2, and
10589558Sgdamore@opensolaris.org 	 * less than the maximum.
10599558Sgdamore@opensolaris.org 	 */
10609558Sgdamore@opensolaris.org 	bufsz = ((*fragp) >> 16) * (1U << (*fragp));
10619558Sgdamore@opensolaris.org 	if (bufsz >= 65536) {
10629558Sgdamore@opensolaris.org 		return (0);
10639558Sgdamore@opensolaris.org 	}
10649558Sgdamore@opensolaris.org 
10659558Sgdamore@opensolaris.org 	/*
10669558Sgdamore@opensolaris.org 	 * We set the latency hints in terms of bytes, not fragments.
10679558Sgdamore@opensolaris.org 	 */
10689558Sgdamore@opensolaris.org 	auclnt_set_latency(auclnt_output_stream(c), 0, bufsz);
10699558Sgdamore@opensolaris.org 	auclnt_set_latency(auclnt_input_stream(c), 0, bufsz);
10709558Sgdamore@opensolaris.org 
10719558Sgdamore@opensolaris.org 	/*
10729484Sgarrett.damore@Sun.COM 	 * According to the OSS API documentation, the values provided
10739484Sgarrett.damore@Sun.COM 	 * are nothing more than a "hint" and not to be relied upon
10749484Sgarrett.damore@Sun.COM 	 * anyway.  And we aren't obligated to report the actual
10759484Sgarrett.damore@Sun.COM 	 * values back!
10769484Sgarrett.damore@Sun.COM 	 */
10779484Sgarrett.damore@Sun.COM 	return (0);
10789484Sgarrett.damore@Sun.COM }
10799484Sgarrett.damore@Sun.COM 
10809558Sgdamore@opensolaris.org static int
sndctl_dsp_policy(audio_client_t * c,int * policy)10819558Sgdamore@opensolaris.org sndctl_dsp_policy(audio_client_t *c, int *policy)
10829558Sgdamore@opensolaris.org {
10839558Sgdamore@opensolaris.org 	int	hint = *policy;
10849558Sgdamore@opensolaris.org 	if ((hint >= 2) && (hint <= 10)) {
10859558Sgdamore@opensolaris.org 		auclnt_set_latency(auclnt_input_stream(c), hint, 0);
10869558Sgdamore@opensolaris.org 		auclnt_set_latency(auclnt_output_stream(c), hint, 0);
10879558Sgdamore@opensolaris.org 	}
10889558Sgdamore@opensolaris.org 	return (0);
10899558Sgdamore@opensolaris.org }
10909558Sgdamore@opensolaris.org 
10919484Sgarrett.damore@Sun.COM /*
10929484Sgarrett.damore@Sun.COM  * A word about recsrc, and playtgt ioctls: We don't allow ordinary DSP
10939484Sgarrett.damore@Sun.COM  * applications to change port configurations, because these could have a
10949484Sgarrett.damore@Sun.COM  * bad effect for other applications.  Instead, these settings have to
10959484Sgarrett.damore@Sun.COM  * be changed using the master mixer panel.  In order to make applications
10969484Sgarrett.damore@Sun.COM  * happy, we just present a single "default" source/target.
10979484Sgarrett.damore@Sun.COM  */
10989484Sgarrett.damore@Sun.COM static int
sndctl_dsp_get_recsrc_names(audio_client_t * c,oss_mixer_enuminfo * ei)10999484Sgarrett.damore@Sun.COM sndctl_dsp_get_recsrc_names(audio_client_t *c, oss_mixer_enuminfo *ei)
11009484Sgarrett.damore@Sun.COM {
11019484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
11029484Sgarrett.damore@Sun.COM 
11039484Sgarrett.damore@Sun.COM 	ei->nvalues = 1;
11049484Sgarrett.damore@Sun.COM 	(void) snprintf(ei->strings, sizeof (ei->strings), "default");
11059484Sgarrett.damore@Sun.COM 	ei->strindex[0] = 0;
11069484Sgarrett.damore@Sun.COM 
11079484Sgarrett.damore@Sun.COM 	return (0);
11089484Sgarrett.damore@Sun.COM }
11099484Sgarrett.damore@Sun.COM 
11109484Sgarrett.damore@Sun.COM static int
sndctl_dsp_get_recsrc(audio_client_t * c,int * srcp)11119484Sgarrett.damore@Sun.COM sndctl_dsp_get_recsrc(audio_client_t *c, int *srcp)
11129484Sgarrett.damore@Sun.COM {
11139484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
11149484Sgarrett.damore@Sun.COM 	*srcp = 0;
11159484Sgarrett.damore@Sun.COM 	return (0);
11169484Sgarrett.damore@Sun.COM }
11179484Sgarrett.damore@Sun.COM 
11189484Sgarrett.damore@Sun.COM static int
sndctl_dsp_set_recsrc(audio_client_t * c,int * srcp)11199484Sgarrett.damore@Sun.COM sndctl_dsp_set_recsrc(audio_client_t *c, int *srcp)
11209484Sgarrett.damore@Sun.COM {
11219484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
11229484Sgarrett.damore@Sun.COM 	*srcp = 0;
11239484Sgarrett.damore@Sun.COM 	return (0);
11249484Sgarrett.damore@Sun.COM }
11259484Sgarrett.damore@Sun.COM 
11269484Sgarrett.damore@Sun.COM static int
sndctl_dsp_get_playtgt_names(audio_client_t * c,oss_mixer_enuminfo * ei)11279484Sgarrett.damore@Sun.COM sndctl_dsp_get_playtgt_names(audio_client_t *c, oss_mixer_enuminfo *ei)
11289484Sgarrett.damore@Sun.COM {
11299484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
11309484Sgarrett.damore@Sun.COM 
11319484Sgarrett.damore@Sun.COM 	ei->nvalues = 1;
11329484Sgarrett.damore@Sun.COM 	(void) snprintf(ei->strings, sizeof (ei->strings), "default");
11339484Sgarrett.damore@Sun.COM 	ei->strindex[0] = 0;
11349484Sgarrett.damore@Sun.COM 
11359484Sgarrett.damore@Sun.COM 	return (0);
11369484Sgarrett.damore@Sun.COM }
11379484Sgarrett.damore@Sun.COM 
11389484Sgarrett.damore@Sun.COM static int
sndctl_dsp_get_playtgt(audio_client_t * c,int * tgtp)11399484Sgarrett.damore@Sun.COM sndctl_dsp_get_playtgt(audio_client_t *c, int *tgtp)
11409484Sgarrett.damore@Sun.COM {
11419484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
11429484Sgarrett.damore@Sun.COM 	*tgtp = 0;
11439484Sgarrett.damore@Sun.COM 	return (0);
11449484Sgarrett.damore@Sun.COM }
11459484Sgarrett.damore@Sun.COM 
11469484Sgarrett.damore@Sun.COM static int
sndctl_dsp_set_playtgt(audio_client_t * c,int * tgtp)11479484Sgarrett.damore@Sun.COM sndctl_dsp_set_playtgt(audio_client_t *c, int *tgtp)
11489484Sgarrett.damore@Sun.COM {
11499484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
11509484Sgarrett.damore@Sun.COM 	*tgtp = 0;
11519484Sgarrett.damore@Sun.COM 	return (0);
11529484Sgarrett.damore@Sun.COM }
11539484Sgarrett.damore@Sun.COM 
11549484Sgarrett.damore@Sun.COM static int
sndctl_sysinfo(oss_sysinfo * si)11559484Sgarrett.damore@Sun.COM sndctl_sysinfo(oss_sysinfo *si)
11569484Sgarrett.damore@Sun.COM {
11579484Sgarrett.damore@Sun.COM 	bzero(si, sizeof (*si));
11589484Sgarrett.damore@Sun.COM 	(void) snprintf(si->product, sizeof (si->product), "SunOS Audio");
11599484Sgarrett.damore@Sun.COM 	(void) snprintf(si->version, sizeof (si->version), "4.0");
11609484Sgarrett.damore@Sun.COM 	si->versionnum = OSS_VERSION;
11619484Sgarrett.damore@Sun.COM 	si->numcards = oss_cnt_devs();
11629484Sgarrett.damore@Sun.COM 	si->nummixers = si->numcards - 1;
11639484Sgarrett.damore@Sun.COM 	si->numaudios = si->numcards - 1;
11649484Sgarrett.damore@Sun.COM 	si->numaudioengines = si->numaudios;
11659484Sgarrett.damore@Sun.COM 	(void) snprintf(si->license, sizeof (si->license), "CDDL");
11669484Sgarrett.damore@Sun.COM 	return (0);
11679484Sgarrett.damore@Sun.COM }
11689484Sgarrett.damore@Sun.COM 
11699484Sgarrett.damore@Sun.COM static int
sndctl_cardinfo(audio_client_t * c,oss_card_info * ci)11709484Sgarrett.damore@Sun.COM sndctl_cardinfo(audio_client_t *c, oss_card_info *ci)
11719484Sgarrett.damore@Sun.COM {
11729484Sgarrett.damore@Sun.COM 	audio_dev_t	*d;
11739484Sgarrett.damore@Sun.COM 	void		*iter;
11749484Sgarrett.damore@Sun.COM 	const char 	*info;
11759484Sgarrett.damore@Sun.COM 	int		n;
11769484Sgarrett.damore@Sun.COM 	boolean_t	release;
11779484Sgarrett.damore@Sun.COM 
11789484Sgarrett.damore@Sun.COM 	if ((n = ci->card) == -1) {
11799484Sgarrett.damore@Sun.COM 		release = B_FALSE;
11809484Sgarrett.damore@Sun.COM 		d = auclnt_get_dev(c);
11819484Sgarrett.damore@Sun.COM 		n = auclnt_get_dev_index(d);
11829484Sgarrett.damore@Sun.COM 	} else {
11839484Sgarrett.damore@Sun.COM 		release = B_TRUE;
11849484Sgarrett.damore@Sun.COM 		d = auclnt_hold_dev_by_index(n);
11859484Sgarrett.damore@Sun.COM 	}
11869484Sgarrett.damore@Sun.COM 
11879484Sgarrett.damore@Sun.COM 	bzero(ci, sizeof (*ci));
11889484Sgarrett.damore@Sun.COM 	ci->card = n;
11899484Sgarrett.damore@Sun.COM 
11909484Sgarrett.damore@Sun.COM 	if (d == NULL) {
11919484Sgarrett.damore@Sun.COM 		/*
11929484Sgarrett.damore@Sun.COM 		 * If device removed (e.g. for DR), then
11939484Sgarrett.damore@Sun.COM 		 * report a bogus removed entry.
11949484Sgarrett.damore@Sun.COM 		 */
11959484Sgarrett.damore@Sun.COM 		(void) snprintf(ci->shortname, sizeof (ci->shortname),
11969484Sgarrett.damore@Sun.COM 		    "<removed>");
11979484Sgarrett.damore@Sun.COM 		(void) snprintf(ci->longname, sizeof (ci->longname),
11989484Sgarrett.damore@Sun.COM 		    "<removed>");
11999484Sgarrett.damore@Sun.COM 		return (0);
12009484Sgarrett.damore@Sun.COM 	}
12019484Sgarrett.damore@Sun.COM 
12029484Sgarrett.damore@Sun.COM 	(void) snprintf(ci->shortname, sizeof (ci->shortname),
12039484Sgarrett.damore@Sun.COM 	    "%s", auclnt_get_dev_name(d));
12049484Sgarrett.damore@Sun.COM 	(void) snprintf(ci->longname, sizeof (ci->longname),
12059484Sgarrett.damore@Sun.COM 	    "%s (%s)", auclnt_get_dev_description(d),
12069484Sgarrett.damore@Sun.COM 	    auclnt_get_dev_version(d));
12079484Sgarrett.damore@Sun.COM 
12089484Sgarrett.damore@Sun.COM 	iter = NULL;
12099484Sgarrett.damore@Sun.COM 	while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) {
12109484Sgarrett.damore@Sun.COM 		(void) strlcat(ci->hw_info, info, sizeof (ci->hw_info));
12119484Sgarrett.damore@Sun.COM 		(void) strlcat(ci->hw_info, "\n", sizeof (ci->hw_info));
12129484Sgarrett.damore@Sun.COM 	}
12139484Sgarrett.damore@Sun.COM 
12149484Sgarrett.damore@Sun.COM 	/*
12159484Sgarrett.damore@Sun.COM 	 * We don't report interrupt counts, ack counts (which are
12169484Sgarrett.damore@Sun.COM 	 * just "read" interrupts, not spurious), or any other flags.
12179484Sgarrett.damore@Sun.COM 	 * Nothing should be using any of this data anyway ... these
12189484Sgarrett.damore@Sun.COM 	 * values were intended for 4Front's debugging purposes.  In
12199484Sgarrett.damore@Sun.COM 	 * Solaris, drivers should use interrupt kstats to report
12209484Sgarrett.damore@Sun.COM 	 * interrupt related statistics.
12219484Sgarrett.damore@Sun.COM 	 */
12229484Sgarrett.damore@Sun.COM 	if (release)
12239484Sgarrett.damore@Sun.COM 		auclnt_release_dev(d);
12249484Sgarrett.damore@Sun.COM 	return (0);
12259484Sgarrett.damore@Sun.COM }
12269484Sgarrett.damore@Sun.COM 
12279484Sgarrett.damore@Sun.COM static int
audioinfo_walker(audio_engine_t * e,void * a)12289484Sgarrett.damore@Sun.COM audioinfo_walker(audio_engine_t *e, void *a)
12299484Sgarrett.damore@Sun.COM {
12309484Sgarrett.damore@Sun.COM 	oss_audioinfo *si = a;
12319484Sgarrett.damore@Sun.COM 	int fmt, nchan, rate, cap;
12329484Sgarrett.damore@Sun.COM 
12339484Sgarrett.damore@Sun.COM 	fmt = auclnt_engine_get_format(e);
12349484Sgarrett.damore@Sun.COM 	nchan = auclnt_engine_get_channels(e);
12359484Sgarrett.damore@Sun.COM 	rate = auclnt_engine_get_rate(e);
12369484Sgarrett.damore@Sun.COM 	cap = auclnt_engine_get_capab(e);
12379484Sgarrett.damore@Sun.COM 
12389484Sgarrett.damore@Sun.COM 	for (int i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) {
12399484Sgarrett.damore@Sun.COM 		if (fmt == oss_formats[i].fmt) {
12409484Sgarrett.damore@Sun.COM 			if (cap & AUDIO_CLIENT_CAP_PLAY) {
12419484Sgarrett.damore@Sun.COM 				si->oformats |= oss_formats[i].oss;
12429484Sgarrett.damore@Sun.COM 			}
12439484Sgarrett.damore@Sun.COM 			if (cap & AUDIO_CLIENT_CAP_RECORD) {
12449484Sgarrett.damore@Sun.COM 				si->iformats |= oss_formats[i].oss;
12459484Sgarrett.damore@Sun.COM 			}
12469484Sgarrett.damore@Sun.COM 			break;
12479484Sgarrett.damore@Sun.COM 		}
12489484Sgarrett.damore@Sun.COM 	}
12499484Sgarrett.damore@Sun.COM 	si->max_channels = max(nchan, si->max_channels);
12509484Sgarrett.damore@Sun.COM 	si->max_rate = max(rate, si->max_rate);
12519484Sgarrett.damore@Sun.COM 
12529484Sgarrett.damore@Sun.COM 	return (AUDIO_WALK_CONTINUE);
12539484Sgarrett.damore@Sun.COM }
12549484Sgarrett.damore@Sun.COM 
12559484Sgarrett.damore@Sun.COM static int
sndctl_audioinfo(audio_client_t * c,oss_audioinfo * si)12569484Sgarrett.damore@Sun.COM sndctl_audioinfo(audio_client_t *c, oss_audioinfo *si)
12579484Sgarrett.damore@Sun.COM {
12589484Sgarrett.damore@Sun.COM 	audio_dev_t		*d;
12599484Sgarrett.damore@Sun.COM 	const char		*name;
12609484Sgarrett.damore@Sun.COM 	int			n;
12619484Sgarrett.damore@Sun.COM 	boolean_t		release;
12629484Sgarrett.damore@Sun.COM 	unsigned		cap;
12639484Sgarrett.damore@Sun.COM 
12649484Sgarrett.damore@Sun.COM 	if ((n = si->dev) == -1) {
12659484Sgarrett.damore@Sun.COM 		release = B_FALSE;
12669484Sgarrett.damore@Sun.COM 		d = auclnt_get_dev(c);
12679484Sgarrett.damore@Sun.COM 		n = auclnt_get_dev_index(d);
12689484Sgarrett.damore@Sun.COM 	} else {
12699484Sgarrett.damore@Sun.COM 		release = B_TRUE;
12709484Sgarrett.damore@Sun.COM 		n++;	/* skip pseudo device */
12719484Sgarrett.damore@Sun.COM 		d = auclnt_hold_dev_by_index(n);
12729484Sgarrett.damore@Sun.COM 	}
12739484Sgarrett.damore@Sun.COM 
12749484Sgarrett.damore@Sun.COM 	bzero(si, sizeof (*si));
12759484Sgarrett.damore@Sun.COM 	si->dev = n - 1;
12769484Sgarrett.damore@Sun.COM 
12779484Sgarrett.damore@Sun.COM 	if (d == NULL) {
12789484Sgarrett.damore@Sun.COM 		/* if device not present, forge a false entry */
12799484Sgarrett.damore@Sun.COM 		si->card_number = n;
12809484Sgarrett.damore@Sun.COM 		si->mixer_dev = n - 1;
12819484Sgarrett.damore@Sun.COM 		si->legacy_device = -1;
12829484Sgarrett.damore@Sun.COM 		si->enabled = 0;
12839484Sgarrett.damore@Sun.COM 		(void) snprintf(si->name, sizeof (si->name), "<removed>");
12849484Sgarrett.damore@Sun.COM 		return (0);
12859484Sgarrett.damore@Sun.COM 	}
12869484Sgarrett.damore@Sun.COM 
12879484Sgarrett.damore@Sun.COM 	name = auclnt_get_dev_name(d);
12889484Sgarrett.damore@Sun.COM 	(void) snprintf(si->name, sizeof (si->name), "%s", name);
12899484Sgarrett.damore@Sun.COM 
12909484Sgarrett.damore@Sun.COM 	si->legacy_device = auclnt_get_dev_number(d);
12919484Sgarrett.damore@Sun.COM 	si->caps = 0;
12929484Sgarrett.damore@Sun.COM 
12939484Sgarrett.damore@Sun.COM 	auclnt_dev_walk_engines(d, audioinfo_walker, si);
12949484Sgarrett.damore@Sun.COM 
12959484Sgarrett.damore@Sun.COM 	cap = auclnt_get_dev_capab(d);
12969484Sgarrett.damore@Sun.COM 
12979484Sgarrett.damore@Sun.COM 	if (cap	& AUDIO_CLIENT_CAP_DUPLEX) {
12989484Sgarrett.damore@Sun.COM 		si->caps |= PCM_CAP_DUPLEX;
12999484Sgarrett.damore@Sun.COM 	}
13009484Sgarrett.damore@Sun.COM 	if (cap & AUDIO_CLIENT_CAP_PLAY) {
13019484Sgarrett.damore@Sun.COM 		si->caps |= PCM_CAP_OUTPUT;
13029484Sgarrett.damore@Sun.COM 	}
13039484Sgarrett.damore@Sun.COM 	if (cap & AUDIO_CLIENT_CAP_RECORD) {
13049484Sgarrett.damore@Sun.COM 		si->caps |= PCM_CAP_INPUT;
13059484Sgarrett.damore@Sun.COM 	}
13069484Sgarrett.damore@Sun.COM 
13079484Sgarrett.damore@Sun.COM 	if (si->caps != 0) {
13089484Sgarrett.damore@Sun.COM 		/* MMAP: we add PCM_CAP_MMAP when we we support it */
130910477SGarrett.Damore@Sun.COM 		si->caps |= PCM_CAP_TRIGGER | PCM_CAP_BATCH;
13109484Sgarrett.damore@Sun.COM 		si->enabled = 1;
13119484Sgarrett.damore@Sun.COM 		si->rate_source = si->dev;
13129484Sgarrett.damore@Sun.COM 
131310477SGarrett.Damore@Sun.COM 		/* we can convert and mix PCM formats */
131410477SGarrett.Damore@Sun.COM 		if (!(cap & AUDIO_CLIENT_CAP_OPAQUE)) {
13159484Sgarrett.damore@Sun.COM 			si->min_channels = min(2, si->max_channels);
13169484Sgarrett.damore@Sun.COM 			si->min_rate = min(5000, si->max_rate);
131710477SGarrett.Damore@Sun.COM 			si->caps |= PCM_CAP_FREERATE | PCM_CAP_MULTI;
13189484Sgarrett.damore@Sun.COM 		}
13199484Sgarrett.damore@Sun.COM 		(void) snprintf(si->devnode, sizeof (si->devnode),
13209484Sgarrett.damore@Sun.COM 		    "/dev/sound/%s:%ddsp",
13219484Sgarrett.damore@Sun.COM 		    auclnt_get_dev_driver(d), auclnt_get_dev_instance(d));
13229484Sgarrett.damore@Sun.COM 	} else {
13239484Sgarrett.damore@Sun.COM 		si->enabled = 0;	/* stops apps from using us directly */
13249484Sgarrett.damore@Sun.COM 		si->caps = PCM_CAP_VIRTUAL;
13259484Sgarrett.damore@Sun.COM 		(void) snprintf(si->devnode, sizeof (si->devnode),
13269484Sgarrett.damore@Sun.COM 		    "/dev/sndstat");
13279484Sgarrett.damore@Sun.COM 	}
13289484Sgarrett.damore@Sun.COM 
13299484Sgarrett.damore@Sun.COM 	si->pid = -1;
13309484Sgarrett.damore@Sun.COM 	(void) snprintf(si->handle, sizeof (si->handle), "%s", name);
13319484Sgarrett.damore@Sun.COM 	(void) snprintf(si->label, sizeof (si->label), "%s", name);
13329484Sgarrett.damore@Sun.COM 	si->latency = -1;
13339484Sgarrett.damore@Sun.COM 	si->card_number = n;
13349484Sgarrett.damore@Sun.COM 	si->mixer_dev = n - 1;
13359484Sgarrett.damore@Sun.COM 
13369484Sgarrett.damore@Sun.COM 	if (release)
13379484Sgarrett.damore@Sun.COM 		auclnt_release_dev(d);
13389484Sgarrett.damore@Sun.COM 
13399484Sgarrett.damore@Sun.COM 	return (0);
13409484Sgarrett.damore@Sun.COM }
13419484Sgarrett.damore@Sun.COM 
13429484Sgarrett.damore@Sun.COM static int
sound_mixer_info(audio_client_t * c,mixer_info * mi)13439484Sgarrett.damore@Sun.COM sound_mixer_info(audio_client_t *c, mixer_info *mi)
13449484Sgarrett.damore@Sun.COM {
13459484Sgarrett.damore@Sun.COM 	audio_dev_t	*d;
13469484Sgarrett.damore@Sun.COM 	const char	*name;
13479484Sgarrett.damore@Sun.COM 
13489484Sgarrett.damore@Sun.COM 	d = auclnt_get_dev(c);
13499484Sgarrett.damore@Sun.COM 
13509484Sgarrett.damore@Sun.COM 	name = auclnt_get_dev_name(d);
13519484Sgarrett.damore@Sun.COM 	(void) snprintf(mi->id, sizeof (mi->id), "%s", name);
13529484Sgarrett.damore@Sun.COM 	(void) snprintf(mi->name, sizeof (mi->name), "%s", name);
13539484Sgarrett.damore@Sun.COM 	(void) snprintf(mi->handle, sizeof (mi->handle), "%s", name);
135410632Sgdamore@opensolaris.org 	mi->modify_counter = (int)auclnt_dev_get_serial(d);
13559484Sgarrett.damore@Sun.COM 	mi->card_number = auclnt_get_dev_index(d);
13569484Sgarrett.damore@Sun.COM 	mi->port_number = 0;
13579484Sgarrett.damore@Sun.COM 	return (0);
13589484Sgarrett.damore@Sun.COM }
13599484Sgarrett.damore@Sun.COM 
13609484Sgarrett.damore@Sun.COM static int
sound_mixer_read_devmask(audio_client_t * c,int * devmask)13619484Sgarrett.damore@Sun.COM sound_mixer_read_devmask(audio_client_t *c, int *devmask)
13629484Sgarrett.damore@Sun.COM {
13639484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
13649484Sgarrett.damore@Sun.COM 	*devmask = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_IGAIN;
13659484Sgarrett.damore@Sun.COM 	return (0);
13669484Sgarrett.damore@Sun.COM }
13679484Sgarrett.damore@Sun.COM 
13689484Sgarrett.damore@Sun.COM static int
sound_mixer_read_recmask(audio_client_t * c,int * recmask)13699484Sgarrett.damore@Sun.COM sound_mixer_read_recmask(audio_client_t *c, int *recmask)
13709484Sgarrett.damore@Sun.COM {
13719484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
13729484Sgarrett.damore@Sun.COM 	*recmask = 0;
13739484Sgarrett.damore@Sun.COM 	return (0);
13749484Sgarrett.damore@Sun.COM }
13759484Sgarrett.damore@Sun.COM 
13769484Sgarrett.damore@Sun.COM static int
sound_mixer_read_recsrc(audio_client_t * c,int * recsrc)13779484Sgarrett.damore@Sun.COM sound_mixer_read_recsrc(audio_client_t *c, int *recsrc)
13789484Sgarrett.damore@Sun.COM {
13799484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
13809484Sgarrett.damore@Sun.COM 	*recsrc = 0;
13819484Sgarrett.damore@Sun.COM 	return (0);
13829484Sgarrett.damore@Sun.COM }
13839484Sgarrett.damore@Sun.COM 
13849484Sgarrett.damore@Sun.COM static int
sound_mixer_read_caps(audio_client_t * c,int * caps)13859484Sgarrett.damore@Sun.COM sound_mixer_read_caps(audio_client_t *c, int *caps)
13869484Sgarrett.damore@Sun.COM {
13879484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
13889484Sgarrett.damore@Sun.COM 	/* single recording source... sort of */
13899484Sgarrett.damore@Sun.COM 	*caps = SOUND_CAP_EXCL_INPUT;
13909484Sgarrett.damore@Sun.COM 	return (0);
13919484Sgarrett.damore@Sun.COM }
13929484Sgarrett.damore@Sun.COM 
13939484Sgarrett.damore@Sun.COM static int
sndctl_mixerinfo(audio_client_t * c,oss_mixerinfo * mi)13949484Sgarrett.damore@Sun.COM sndctl_mixerinfo(audio_client_t *c, oss_mixerinfo *mi)
13959484Sgarrett.damore@Sun.COM {
13969484Sgarrett.damore@Sun.COM 	audio_dev_t		*d;
13979484Sgarrett.damore@Sun.COM 	ossdev_t 		*odev;
13989484Sgarrett.damore@Sun.COM 	const char		*name;
13999484Sgarrett.damore@Sun.COM 	int			n;
14009484Sgarrett.damore@Sun.COM 	boolean_t		release = B_FALSE;
14019484Sgarrett.damore@Sun.COM 
14029484Sgarrett.damore@Sun.COM 	if ((n = mi->dev) == -1) {
14039484Sgarrett.damore@Sun.COM 		release = B_FALSE;
14049484Sgarrett.damore@Sun.COM 		d = auclnt_get_dev(c);
14059484Sgarrett.damore@Sun.COM 		n = auclnt_get_dev_index(d);
14069484Sgarrett.damore@Sun.COM 	} else {
14079484Sgarrett.damore@Sun.COM 		release = B_TRUE;
14089484Sgarrett.damore@Sun.COM 		n++;
14099484Sgarrett.damore@Sun.COM 		d = auclnt_hold_dev_by_index(n);
14109484Sgarrett.damore@Sun.COM 	}
14119484Sgarrett.damore@Sun.COM 
14129484Sgarrett.damore@Sun.COM 	bzero(mi, sizeof (*mi));
14139484Sgarrett.damore@Sun.COM 	mi->dev = n - 1;
14149484Sgarrett.damore@Sun.COM 
14159484Sgarrett.damore@Sun.COM 	if (d == NULL) {
14169484Sgarrett.damore@Sun.COM 		mi->card_number = n;
14179484Sgarrett.damore@Sun.COM 		mi->enabled = 0;
14189484Sgarrett.damore@Sun.COM 		mi->legacy_device = -1;
14199484Sgarrett.damore@Sun.COM 		(void) snprintf(mi->name, sizeof (mi->name), "<removed>");
14209484Sgarrett.damore@Sun.COM 		(void) snprintf(mi->id, sizeof (mi->id), "<removed>");
14219484Sgarrett.damore@Sun.COM 		return (0);
14229484Sgarrett.damore@Sun.COM 	}
14239484Sgarrett.damore@Sun.COM 
14249484Sgarrett.damore@Sun.COM 	if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) {
14259484Sgarrett.damore@Sun.COM 		if (release)
14269484Sgarrett.damore@Sun.COM 			auclnt_release_dev(d);
14279484Sgarrett.damore@Sun.COM 		return (EINVAL);
14289484Sgarrett.damore@Sun.COM 	}
14299484Sgarrett.damore@Sun.COM 
14309484Sgarrett.damore@Sun.COM 	name = auclnt_get_dev_name(d);
14319484Sgarrett.damore@Sun.COM 	(void) snprintf(mi->name, sizeof (mi->name), "%s", name);
14329484Sgarrett.damore@Sun.COM 	(void) snprintf(mi->id, sizeof (mi->id), "%s", name);
14339484Sgarrett.damore@Sun.COM 	(void) snprintf(mi->handle, sizeof (mi->handle), "%s", name);
143410632Sgdamore@opensolaris.org 	mi->modify_counter = (int)auclnt_dev_get_serial(d);
14359484Sgarrett.damore@Sun.COM 	mi->card_number = auclnt_get_dev_index(d);
14369484Sgarrett.damore@Sun.COM 	mi->legacy_device = auclnt_get_dev_number(d);
14379484Sgarrett.damore@Sun.COM 	if (mi->legacy_device >= 0) {
14389484Sgarrett.damore@Sun.COM 		(void) snprintf(mi->devnode, sizeof (mi->devnode),
14399484Sgarrett.damore@Sun.COM 		    "/dev/sound/%s:%dmixer",
14409484Sgarrett.damore@Sun.COM 		    auclnt_get_dev_driver(d), auclnt_get_dev_instance(d));
14419484Sgarrett.damore@Sun.COM 		mi->enabled = 1;
14429484Sgarrett.damore@Sun.COM 	} else {
14439484Sgarrett.damore@Sun.COM 		/* special nodes use generic sndstat node */
14449484Sgarrett.damore@Sun.COM 		(void) snprintf(mi->devnode, sizeof (mi->devnode),
14459484Sgarrett.damore@Sun.COM 		    "/dev/sndstat");
14469484Sgarrett.damore@Sun.COM 		mi->enabled = 0;
14479484Sgarrett.damore@Sun.COM 	}
14489484Sgarrett.damore@Sun.COM 	mi->nrext = odev->d_nctrl;
14499484Sgarrett.damore@Sun.COM 
14509484Sgarrett.damore@Sun.COM 	if (release)
14519484Sgarrett.damore@Sun.COM 		auclnt_release_dev(d);
14529484Sgarrett.damore@Sun.COM 
14539484Sgarrett.damore@Sun.COM 	return (0);
14549484Sgarrett.damore@Sun.COM }
14559484Sgarrett.damore@Sun.COM 
14569484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getblksize(audio_client_t * c,int * fragsz)14579484Sgarrett.damore@Sun.COM sndctl_dsp_getblksize(audio_client_t *c, int *fragsz)
14589484Sgarrett.damore@Sun.COM {
14599484Sgarrett.damore@Sun.COM 	int	oflag = auclnt_get_oflag(c);
14609484Sgarrett.damore@Sun.COM 
14619484Sgarrett.damore@Sun.COM 	if (oflag & FWRITE)
14629484Sgarrett.damore@Sun.COM 		*fragsz  = auclnt_get_fragsz(auclnt_output_stream(c));
14639484Sgarrett.damore@Sun.COM 	else if (oflag & FREAD)
14649484Sgarrett.damore@Sun.COM 		*fragsz  = auclnt_get_fragsz(auclnt_input_stream(c));
14659484Sgarrett.damore@Sun.COM 
14669484Sgarrett.damore@Sun.COM 	return (0);
14679484Sgarrett.damore@Sun.COM }
14689484Sgarrett.damore@Sun.COM 
14699484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getospace(audio_client_t * c,audio_buf_info * bi)14709484Sgarrett.damore@Sun.COM sndctl_dsp_getospace(audio_client_t *c, audio_buf_info *bi)
14719484Sgarrett.damore@Sun.COM {
14729484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp;
14739484Sgarrett.damore@Sun.COM 	unsigned	n;
14749484Sgarrett.damore@Sun.COM 
14759484Sgarrett.damore@Sun.COM 	if ((auclnt_get_oflag(c) & FWRITE) == 0) {
14769484Sgarrett.damore@Sun.COM 		return (EACCES);
14779484Sgarrett.damore@Sun.COM 	}
14789484Sgarrett.damore@Sun.COM 
14799484Sgarrett.damore@Sun.COM 	sp = auclnt_output_stream(c);
14809484Sgarrett.damore@Sun.COM 	n = auclnt_get_nframes(sp) - auclnt_get_count(sp);
14819484Sgarrett.damore@Sun.COM 
14829484Sgarrett.damore@Sun.COM 	bi->fragsize  = auclnt_get_fragsz(sp);
14839484Sgarrett.damore@Sun.COM 	bi->fragstotal = auclnt_get_nfrags(sp);
14849484Sgarrett.damore@Sun.COM 	bi->bytes = (n * auclnt_get_framesz(sp));
14859484Sgarrett.damore@Sun.COM 	bi->fragments = bi->bytes / bi->fragsize;
14869484Sgarrett.damore@Sun.COM 
14879484Sgarrett.damore@Sun.COM 	return (0);
14889484Sgarrett.damore@Sun.COM }
14899484Sgarrett.damore@Sun.COM 
14909484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getispace(audio_client_t * c,audio_buf_info * bi)14919484Sgarrett.damore@Sun.COM sndctl_dsp_getispace(audio_client_t *c, audio_buf_info *bi)
14929484Sgarrett.damore@Sun.COM {
14939484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp;
14949484Sgarrett.damore@Sun.COM 	unsigned	n;
14959484Sgarrett.damore@Sun.COM 
14969484Sgarrett.damore@Sun.COM 	if ((auclnt_get_oflag(c) & FREAD) == 0) {
14979484Sgarrett.damore@Sun.COM 		return (EACCES);
14989484Sgarrett.damore@Sun.COM 	}
14999484Sgarrett.damore@Sun.COM 
15009484Sgarrett.damore@Sun.COM 	sp = auclnt_input_stream(c);
15019484Sgarrett.damore@Sun.COM 	n = auclnt_get_count(sp);
15029484Sgarrett.damore@Sun.COM 
15039484Sgarrett.damore@Sun.COM 	bi->fragsize  = auclnt_get_fragsz(sp);
15049484Sgarrett.damore@Sun.COM 	bi->fragstotal = auclnt_get_nfrags(sp);
15059484Sgarrett.damore@Sun.COM 	bi->bytes = (n * auclnt_get_framesz(sp));
15069484Sgarrett.damore@Sun.COM 	bi->fragments = bi->bytes / bi->fragsize;
15079484Sgarrett.damore@Sun.COM 
15089484Sgarrett.damore@Sun.COM 	return (0);
15099484Sgarrett.damore@Sun.COM }
15109484Sgarrett.damore@Sun.COM 
15119484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getodelay(audio_client_t * c,int * bytes)15129484Sgarrett.damore@Sun.COM sndctl_dsp_getodelay(audio_client_t *c, int *bytes)
15139484Sgarrett.damore@Sun.COM {
15149484Sgarrett.damore@Sun.COM 	unsigned	framesz;
15159484Sgarrett.damore@Sun.COM 	unsigned	slen, flen;
15169484Sgarrett.damore@Sun.COM 
15179484Sgarrett.damore@Sun.COM 	if (auclnt_get_oflag(c) & FWRITE) {
15189484Sgarrett.damore@Sun.COM 		audio_stream_t	*sp = auclnt_output_stream(c);
15199484Sgarrett.damore@Sun.COM 		framesz = auclnt_get_framesz(sp);
15209484Sgarrett.damore@Sun.COM 		auclnt_get_output_qlen(c, &slen, &flen);
15219484Sgarrett.damore@Sun.COM 		*bytes = (slen + flen) * framesz;
15229484Sgarrett.damore@Sun.COM 	} else {
15239484Sgarrett.damore@Sun.COM 		*bytes = 0;
15249484Sgarrett.damore@Sun.COM 	}
15259484Sgarrett.damore@Sun.COM 	return (0);
15269484Sgarrett.damore@Sun.COM }
15279484Sgarrett.damore@Sun.COM 
15289484Sgarrett.damore@Sun.COM static int
sndctl_dsp_current_iptr(audio_client_t * c,oss_count_t * count)15299484Sgarrett.damore@Sun.COM sndctl_dsp_current_iptr(audio_client_t *c, oss_count_t *count)
15309484Sgarrett.damore@Sun.COM {
15319484Sgarrett.damore@Sun.COM 	if (auclnt_get_oflag(c) & FREAD) {
15329484Sgarrett.damore@Sun.COM 		count->samples = auclnt_get_samples(auclnt_input_stream(c));
15339484Sgarrett.damore@Sun.COM 		count->fifo_samples = 0;	/* not quite accurate */
15349484Sgarrett.damore@Sun.COM 	} else {
15359484Sgarrett.damore@Sun.COM 		count->samples = 0;
15369484Sgarrett.damore@Sun.COM 		count->fifo_samples = 0;
15379484Sgarrett.damore@Sun.COM 	}
15389484Sgarrett.damore@Sun.COM 	return (0);
15399484Sgarrett.damore@Sun.COM }
15409484Sgarrett.damore@Sun.COM 
15419484Sgarrett.damore@Sun.COM static int
sndctl_dsp_current_optr(audio_client_t * c,oss_count_t * count)15429484Sgarrett.damore@Sun.COM sndctl_dsp_current_optr(audio_client_t *c, oss_count_t *count)
15439484Sgarrett.damore@Sun.COM {
15449484Sgarrett.damore@Sun.COM 	unsigned samples, fifo;
15459484Sgarrett.damore@Sun.COM 
15469484Sgarrett.damore@Sun.COM 	if (auclnt_get_oflag(c) & FWRITE) {
15479484Sgarrett.damore@Sun.COM 		auclnt_get_output_qlen(c, &samples, &fifo);
15489484Sgarrett.damore@Sun.COM 		count->samples = samples;
15499484Sgarrett.damore@Sun.COM 		count->fifo_samples = fifo;
15509484Sgarrett.damore@Sun.COM 	} else {
15519484Sgarrett.damore@Sun.COM 		count->samples = 0;
15529484Sgarrett.damore@Sun.COM 		count->fifo_samples = 0;
15539484Sgarrett.damore@Sun.COM 	}
15549484Sgarrett.damore@Sun.COM 	return (0);
15559484Sgarrett.damore@Sun.COM }
15569484Sgarrett.damore@Sun.COM 
15579484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getoptr(audio_client_t * c,count_info * ci)15589484Sgarrett.damore@Sun.COM sndctl_dsp_getoptr(audio_client_t *c, count_info *ci)
15599484Sgarrett.damore@Sun.COM {
15609484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp;
15619484Sgarrett.damore@Sun.COM 	unsigned	framesz;
15629484Sgarrett.damore@Sun.COM 	unsigned	fragsz;
15639484Sgarrett.damore@Sun.COM 
15649484Sgarrett.damore@Sun.COM 	bzero(ci, sizeof (*ci));
15659484Sgarrett.damore@Sun.COM 	if ((auclnt_get_oflag(c) & FWRITE) == 0) {
15669484Sgarrett.damore@Sun.COM 		return (0);
15679484Sgarrett.damore@Sun.COM 	}
15689484Sgarrett.damore@Sun.COM 	sp = auclnt_output_stream(c);
15699484Sgarrett.damore@Sun.COM 	framesz = auclnt_get_framesz(sp);
15709484Sgarrett.damore@Sun.COM 	fragsz = auclnt_get_fragsz(sp);
15719484Sgarrett.damore@Sun.COM 	ci->blocks = auclnt_get_samples(sp) * framesz / fragsz;
15729484Sgarrett.damore@Sun.COM 	auclnt_set_samples(sp, 0);
15739484Sgarrett.damore@Sun.COM 	ci->bytes = auclnt_get_tail(sp) * framesz;
15749484Sgarrett.damore@Sun.COM 	ci->ptr = auclnt_get_tidx(sp) * framesz;
15759484Sgarrett.damore@Sun.COM 	return (0);
15769484Sgarrett.damore@Sun.COM }
15779484Sgarrett.damore@Sun.COM 
15789484Sgarrett.damore@Sun.COM static int
sndctl_dsp_getiptr(audio_client_t * c,count_info * ci)15799484Sgarrett.damore@Sun.COM sndctl_dsp_getiptr(audio_client_t *c, count_info *ci)
15809484Sgarrett.damore@Sun.COM {
15819484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp;
15829484Sgarrett.damore@Sun.COM 	unsigned	framesz;
15839484Sgarrett.damore@Sun.COM 	unsigned	fragsz;
15849484Sgarrett.damore@Sun.COM 
15859484Sgarrett.damore@Sun.COM 	bzero(ci, sizeof (*ci));
15869484Sgarrett.damore@Sun.COM 	if ((auclnt_get_oflag(c) & FREAD) == 0) {
15879484Sgarrett.damore@Sun.COM 		return (0);
15889484Sgarrett.damore@Sun.COM 	}
15899484Sgarrett.damore@Sun.COM 	sp = auclnt_input_stream(c);
15909484Sgarrett.damore@Sun.COM 	framesz = auclnt_get_framesz(sp);
15919484Sgarrett.damore@Sun.COM 	fragsz = auclnt_get_fragsz(sp);
15929484Sgarrett.damore@Sun.COM 	ci->blocks = auclnt_get_samples(sp) * framesz / fragsz;
15939484Sgarrett.damore@Sun.COM 	auclnt_set_samples(sp, 0);
15949484Sgarrett.damore@Sun.COM 	ci->bytes = auclnt_get_head(sp) * framesz;
15959484Sgarrett.damore@Sun.COM 	ci->ptr = auclnt_get_hidx(sp) * framesz;
15969484Sgarrett.damore@Sun.COM 	return (0);
15979484Sgarrett.damore@Sun.COM }
15989484Sgarrett.damore@Sun.COM 
15999484Sgarrett.damore@Sun.COM static int
sndctl_dsp_geterror(audio_client_t * c,audio_errinfo * bi)16009484Sgarrett.damore@Sun.COM sndctl_dsp_geterror(audio_client_t *c, audio_errinfo *bi)
16019484Sgarrett.damore@Sun.COM {
16029484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp;
16039484Sgarrett.damore@Sun.COM 	unsigned	fragsz;
16049484Sgarrett.damore@Sun.COM 	/*
16059484Sgarrett.damore@Sun.COM 	 * Note: The use of this structure is unsafe... different
16069484Sgarrett.damore@Sun.COM 	 * meanings for error codes are used by different implementations,
16079484Sgarrett.damore@Sun.COM 	 * according to the spec.  (Even different versions of the same
16089484Sgarrett.damore@Sun.COM 	 * implementation could have different values.)
16099484Sgarrett.damore@Sun.COM 	 *
16109484Sgarrett.damore@Sun.COM 	 * Rather than try to come up with a reliable solution here, we
16119484Sgarrett.damore@Sun.COM 	 * don't use it.  If you want to report errors, or see the result
16129484Sgarrett.damore@Sun.COM 	 * of errors, use syslog.
16139484Sgarrett.damore@Sun.COM 	 */
16149484Sgarrett.damore@Sun.COM 	bzero(bi, sizeof (*bi));
16159484Sgarrett.damore@Sun.COM 
16169484Sgarrett.damore@Sun.COM 	sp = auclnt_output_stream(c);
16179484Sgarrett.damore@Sun.COM 	fragsz = max(auclnt_get_fragsz(sp), 1);
16189484Sgarrett.damore@Sun.COM 	bi->play_underruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) /
16199484Sgarrett.damore@Sun.COM 	    fragsz);
16209484Sgarrett.damore@Sun.COM 	auclnt_set_errors(sp, 0);
16219484Sgarrett.damore@Sun.COM 
16229484Sgarrett.damore@Sun.COM 	sp = auclnt_input_stream(c);
16239484Sgarrett.damore@Sun.COM 	fragsz = max(auclnt_get_fragsz(sp), 1);
16249484Sgarrett.damore@Sun.COM 	bi->rec_overruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) /
16259484Sgarrett.damore@Sun.COM 	    fragsz);
16269484Sgarrett.damore@Sun.COM 	auclnt_set_errors(sp, 0);
16279484Sgarrett.damore@Sun.COM 
16289484Sgarrett.damore@Sun.COM 	return (0);
16299484Sgarrett.damore@Sun.COM }
16309484Sgarrett.damore@Sun.COM 
16319484Sgarrett.damore@Sun.COM static int
sndctl_sun_send_number(audio_client_t * c,int * num,cred_t * cr)16329484Sgarrett.damore@Sun.COM sndctl_sun_send_number(audio_client_t *c, int *num, cred_t *cr)
16339484Sgarrett.damore@Sun.COM {
16349484Sgarrett.damore@Sun.COM 	audio_dev_t	*dev;
16359484Sgarrett.damore@Sun.COM 	int		rv;
16369484Sgarrett.damore@Sun.COM 
16379484Sgarrett.damore@Sun.COM 	if ((rv = drv_priv(cr)) != 0) {
16389484Sgarrett.damore@Sun.COM 		return (rv);
16399484Sgarrett.damore@Sun.COM 	}
16409484Sgarrett.damore@Sun.COM 
16419484Sgarrett.damore@Sun.COM 	dev = auclnt_get_dev(c);
16429484Sgarrett.damore@Sun.COM 	auclnt_set_dev_number(dev, *num);
16439484Sgarrett.damore@Sun.COM 	return (0);
16449484Sgarrett.damore@Sun.COM }
16459484Sgarrett.damore@Sun.COM 
16469484Sgarrett.damore@Sun.COM static int
oss_getversion(int * versp)16479484Sgarrett.damore@Sun.COM oss_getversion(int *versp)
16489484Sgarrett.damore@Sun.COM {
16499484Sgarrett.damore@Sun.COM 	*versp = OSS_VERSION;
16509484Sgarrett.damore@Sun.COM 	return (0);
16519484Sgarrett.damore@Sun.COM }
16529484Sgarrett.damore@Sun.COM 
16539484Sgarrett.damore@Sun.COM static int
oss_ioctl(audio_client_t * c,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)16549484Sgarrett.damore@Sun.COM oss_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp,
16559484Sgarrett.damore@Sun.COM     int *rvalp)
16569484Sgarrett.damore@Sun.COM {
16579484Sgarrett.damore@Sun.COM 	int	sz;
16589484Sgarrett.damore@Sun.COM 	void	*data;
16599484Sgarrett.damore@Sun.COM 	int	rv = 0;
16609484Sgarrett.damore@Sun.COM 
16619484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(credp));
16629484Sgarrett.damore@Sun.COM 
16639484Sgarrett.damore@Sun.COM 	sz = OSSIOC_GETSZ(cmd);
16649484Sgarrett.damore@Sun.COM 
16659484Sgarrett.damore@Sun.COM 	if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) {
16669484Sgarrett.damore@Sun.COM 		if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) {
16679484Sgarrett.damore@Sun.COM 			return (ENOMEM);
16689484Sgarrett.damore@Sun.COM 		}
16699484Sgarrett.damore@Sun.COM 	} else {
16709484Sgarrett.damore@Sun.COM 		sz = 0;
16719484Sgarrett.damore@Sun.COM 	}
16729484Sgarrett.damore@Sun.COM 
16739484Sgarrett.damore@Sun.COM 	if (cmd & OSSIOC_IN) {
16749484Sgarrett.damore@Sun.COM 		if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) {
16759484Sgarrett.damore@Sun.COM 			goto done;
16769484Sgarrett.damore@Sun.COM 		}
16779484Sgarrett.damore@Sun.COM 	}
16789484Sgarrett.damore@Sun.COM 
16799484Sgarrett.damore@Sun.COM 	switch (cmd) {
16809484Sgarrett.damore@Sun.COM 		/*
16819484Sgarrett.damore@Sun.COM 		 * DSP specific ioctls
16829484Sgarrett.damore@Sun.COM 		 */
16839484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_HALT:
16849484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_halt(c);
16859484Sgarrett.damore@Sun.COM 		break;
16869484Sgarrett.damore@Sun.COM 
16879484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SYNC:
16889484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_sync(c);
16899484Sgarrett.damore@Sun.COM 		break;
16909484Sgarrett.damore@Sun.COM 
16919484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SPEED:
16929484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_speed(c, (int *)data);
16939484Sgarrett.damore@Sun.COM 		break;
16949484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SETFMT:
16959484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_setfmt(c, (int *)data);
16969484Sgarrett.damore@Sun.COM 		break;
16979484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETFMTS:
16989484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getfmts(c, (int *)data);
16999484Sgarrett.damore@Sun.COM 		break;
17009484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_STEREO:
17019484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_stereo(c, (int *)data);
17029484Sgarrett.damore@Sun.COM 		break;
17039484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_CHANNELS:
17049484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_channels(c, (int *)data);
17059484Sgarrett.damore@Sun.COM 		break;
17069484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_POST:
17079484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_post(c);
17089484Sgarrett.damore@Sun.COM 		break;
17099484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETCAPS:
17109484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getcaps(c, (int *)data);
17119484Sgarrett.damore@Sun.COM 		break;
17129484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETTRIGGER:
17139484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_gettrigger(c, (int *)data);
17149484Sgarrett.damore@Sun.COM 		break;
17159484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SETTRIGGER:
17169484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_settrigger(c, (int *)data);
17179484Sgarrett.damore@Sun.COM 		break;
17189484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETPLAYVOL:
17199484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_VOLUME:	/* legacy mixer on dsp */
17209484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_PCM:	/* legacy mixer on dsp */
17219484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_OGAIN:	/* legacy mixer on dsp */
17229484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getplayvol(c, (int *)data);
17239484Sgarrett.damore@Sun.COM 		break;
17249484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_VOLUME:	/* legacy mixer on dsp */
17259484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_PCM:	/* legacy mixer on dsp */
17269484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_OGAIN:	/* legacy mixer on dsp */
17279484Sgarrett.damore@Sun.COM 		rv = sound_mixer_write_ogain(c, (int *)data);
17289484Sgarrett.damore@Sun.COM 		break;
17299484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SETPLAYVOL:
17309484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_setplayvol(c, (int *)data);
17319484Sgarrett.damore@Sun.COM 		break;
17329484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_READCTL:
17339484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_readctl(c, (oss_digital_control *)data);
17349484Sgarrett.damore@Sun.COM 		break;
17359484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_WRITECTL:
17369484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_writectl(c, (oss_digital_control *)data);
17379484Sgarrett.damore@Sun.COM 		break;
17389484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_COOKEDMODE:
17399484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_cookedmode(c, (int *)data);
17409484Sgarrett.damore@Sun.COM 		break;
17419484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SILENCE:
17429484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_silence(c);
17439484Sgarrett.damore@Sun.COM 		break;
17449484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SKIP:
17459484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_skip(c);
17469484Sgarrett.damore@Sun.COM 		break;
17479484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_HALT_INPUT:
17489484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_halt_input(c);
17499484Sgarrett.damore@Sun.COM 		break;
17509484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_HALT_OUTPUT:
17519484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_halt_output(c);
17529484Sgarrett.damore@Sun.COM 		break;
17539484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GET_RECSRC_NAMES:
17549484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_get_recsrc_names(c, (oss_mixer_enuminfo *)data);
17559484Sgarrett.damore@Sun.COM 		break;
17569484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SETFRAGMENT:
17579484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_setfragment(c, (int *)data);
17589484Sgarrett.damore@Sun.COM 		break;
17599484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GET_RECSRC:
17609484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_get_recsrc(c, (int *)data);
17619484Sgarrett.damore@Sun.COM 		break;
17629484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SET_RECSRC:
17639484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_set_recsrc(c, (int *)data);
17649484Sgarrett.damore@Sun.COM 		break;
17659484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GET_PLAYTGT_NAMES:
17669484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_get_playtgt_names(c,
17679484Sgarrett.damore@Sun.COM 		    (oss_mixer_enuminfo *)data);
17689484Sgarrett.damore@Sun.COM 		break;
17699484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GET_PLAYTGT:
17709484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_get_playtgt(c, (int *)data);
17719484Sgarrett.damore@Sun.COM 		break;
17729484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SET_PLAYTGT:
17739484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_set_playtgt(c, (int *)data);
17749484Sgarrett.damore@Sun.COM 		break;
17759484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETRECVOL:
17769484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_RECGAIN:	/* legacy mixer on dsp */
17779484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_RECLEV:	/* legacy mixer on dsp */
17789484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_IGAIN:	/* legacy mixer on dsp */
17799484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getrecvol(c, (int *)data);
17809484Sgarrett.damore@Sun.COM 		break;
17819484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_RECGAIN:	/* legacy mixer on dsp */
17829484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_RECLEV:	/* legacy mixer on dsp */
17839484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_IGAIN:	/* legacy mixer on dsp */
17849484Sgarrett.damore@Sun.COM 		rv = sound_mixer_write_igain(c, (int *)data);
17859484Sgarrett.damore@Sun.COM 		break;
17869484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SETRECVOL:
17879484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_setrecvol(c, (int *)data);
17889484Sgarrett.damore@Sun.COM 		break;
17899558Sgdamore@opensolaris.org 	case SNDCTL_DSP_SUBDIVIDE:	/* Ignored */
17909484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SETDUPLEX:	/* Ignored */
17919484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_LOW_WATER:	/* Ignored */
17929484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_PROFILE:	/* Ignored */
17939484Sgarrett.damore@Sun.COM 		rv = 0;
17949484Sgarrett.damore@Sun.COM 		break;
17959558Sgdamore@opensolaris.org 	case SNDCTL_DSP_POLICY:
17969558Sgdamore@opensolaris.org 		rv = sndctl_dsp_policy(c, (int *)data);
17979558Sgdamore@opensolaris.org 		break;
17989484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETBLKSIZE:
17999484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getblksize(c, (int *)data);
18009484Sgarrett.damore@Sun.COM 		break;
18019484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETOSPACE:
18029484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getospace(c, (audio_buf_info *)data);
18039484Sgarrett.damore@Sun.COM 		break;
18049484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETISPACE:
18059484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getispace(c, (audio_buf_info *)data);
18069484Sgarrett.damore@Sun.COM 		break;
18079484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETODELAY:
18089484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getodelay(c, (int *)data);
18099484Sgarrett.damore@Sun.COM 		break;
18109484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETOPTR:
18119484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getoptr(c, (count_info *)data);
18129484Sgarrett.damore@Sun.COM 		break;
18139484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETIPTR:
18149484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getiptr(c, (count_info *)data);
18159484Sgarrett.damore@Sun.COM 		break;
18169484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETERROR:
18179484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_geterror(c, (audio_errinfo *)data);
18189484Sgarrett.damore@Sun.COM 		break;
18199484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_CURRENT_IPTR:
18209484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_current_iptr(c, (oss_count_t *)data);
18219484Sgarrett.damore@Sun.COM 		break;
18229484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_CURRENT_OPTR:
18239484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_current_optr(c, (oss_count_t *)data);
18249484Sgarrett.damore@Sun.COM 		break;
18259484Sgarrett.damore@Sun.COM 
18269484Sgarrett.damore@Sun.COM 		/*
18279484Sgarrett.damore@Sun.COM 		 * Shared ioctls with /dev/mixer.
18289484Sgarrett.damore@Sun.COM 		 */
18299484Sgarrett.damore@Sun.COM 	case OSS_GETVERSION:
18309484Sgarrett.damore@Sun.COM 		rv = oss_getversion((int *)data);
18319484Sgarrett.damore@Sun.COM 		break;
18329484Sgarrett.damore@Sun.COM 	case SNDCTL_CARDINFO:
18339484Sgarrett.damore@Sun.COM 		rv = sndctl_cardinfo(c, (oss_card_info *)data);
18349484Sgarrett.damore@Sun.COM 		break;
18359484Sgarrett.damore@Sun.COM 	case SNDCTL_ENGINEINFO:
18369484Sgarrett.damore@Sun.COM 	case SNDCTL_AUDIOINFO:
18379484Sgarrett.damore@Sun.COM 	case SNDCTL_AUDIOINFO_EX:
18389484Sgarrett.damore@Sun.COM 		rv = sndctl_audioinfo(c, (oss_audioinfo *)data);
18399484Sgarrett.damore@Sun.COM 		break;
18409484Sgarrett.damore@Sun.COM 	case SNDCTL_SYSINFO:
18419484Sgarrett.damore@Sun.COM 		rv = sndctl_sysinfo((oss_sysinfo *)data);
18429484Sgarrett.damore@Sun.COM 		break;
18439484Sgarrett.damore@Sun.COM 	case SNDCTL_MIXERINFO:
18449484Sgarrett.damore@Sun.COM 		rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data);
18459484Sgarrett.damore@Sun.COM 		break;
18469484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_INFO:
18479484Sgarrett.damore@Sun.COM 		rv = sound_mixer_info(c, (mixer_info *)data);
18489484Sgarrett.damore@Sun.COM 		break;
18499484Sgarrett.damore@Sun.COM 
18509484Sgarrett.damore@Sun.COM 		/*
18519484Sgarrett.damore@Sun.COM 		 * These are mixer ioctls that are virtualized for the DSP
18529484Sgarrett.damore@Sun.COM 		 * device.  They are accessible via either /dev/mixer or
18539484Sgarrett.damore@Sun.COM 		 * /dev/dsp.
18549484Sgarrett.damore@Sun.COM 		 */
18559484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_RECSRC:
18569484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_RECSRC:
18579484Sgarrett.damore@Sun.COM 		rv = sound_mixer_read_recsrc(c, (int *)data);
18589484Sgarrett.damore@Sun.COM 		break;
18599484Sgarrett.damore@Sun.COM 
18609484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_DEVMASK:
18619484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_STEREODEVS:
18629484Sgarrett.damore@Sun.COM 		rv = sound_mixer_read_devmask(c, (int *)data);
18639484Sgarrett.damore@Sun.COM 		break;
18649484Sgarrett.damore@Sun.COM 
18659484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_RECMASK:
18669484Sgarrett.damore@Sun.COM 		rv = sound_mixer_read_recmask(c, (int *)data);
18679484Sgarrett.damore@Sun.COM 		break;
18689484Sgarrett.damore@Sun.COM 
18699484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_CAPS:
18709484Sgarrett.damore@Sun.COM 		rv = sound_mixer_read_caps(c, (int *)data);
18719484Sgarrett.damore@Sun.COM 		break;
18729484Sgarrett.damore@Sun.COM 
18739484Sgarrett.damore@Sun.COM 		/*
18749484Sgarrett.damore@Sun.COM 		 * Ioctls we have chosen not to support for now.  Some
18759484Sgarrett.damore@Sun.COM 		 * of these are of legacy interest only.
18769484Sgarrett.damore@Sun.COM 		 */
18779484Sgarrett.damore@Sun.COM 	case SNDCTL_SETSONG:
18789484Sgarrett.damore@Sun.COM 	case SNDCTL_GETSONG:
18799484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SYNCGROUP:
18809484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SYNCSTART:
18819484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GET_CHNORDER:
18829484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SET_CHNORDER:
18839484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETIPEAKS:
18849484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETOPEAKS:
18859484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_GETCHANNELMASK:
18869484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_BIND_CHANNEL:
18879484Sgarrett.damore@Sun.COM 	case SNDCTL_DSP_SETSYNCRO:
188810477SGarrett.Damore@Sun.COM 	case SNDCTL_DSP_NONBLOCK:
18899484Sgarrett.damore@Sun.COM 	default:
18909484Sgarrett.damore@Sun.COM 		rv = EINVAL;
18919484Sgarrett.damore@Sun.COM 		break;
18929484Sgarrett.damore@Sun.COM 	}
18939484Sgarrett.damore@Sun.COM 
18949484Sgarrett.damore@Sun.COM 	if ((rv == 0) && (cmd & OSSIOC_OUT)) {
18959484Sgarrett.damore@Sun.COM 		rv = ddi_copyout(data, (void *)arg, sz, mode);
18969484Sgarrett.damore@Sun.COM 	}
18979484Sgarrett.damore@Sun.COM 	if (rv == 0) {
18989484Sgarrett.damore@Sun.COM 		*rvalp = 0;
18999484Sgarrett.damore@Sun.COM 	}
19009484Sgarrett.damore@Sun.COM 
19019484Sgarrett.damore@Sun.COM done:
19029484Sgarrett.damore@Sun.COM 	if (sz) {
19039484Sgarrett.damore@Sun.COM 		kmem_free(data, sz);
19049484Sgarrett.damore@Sun.COM 	}
19059484Sgarrett.damore@Sun.COM 	return (rv);
19069484Sgarrett.damore@Sun.COM }
19079484Sgarrett.damore@Sun.COM 
19089484Sgarrett.damore@Sun.COM static void
oss_output(audio_client_t * c)19099484Sgarrett.damore@Sun.COM oss_output(audio_client_t *c)
19109484Sgarrett.damore@Sun.COM {
19119484Sgarrett.damore@Sun.COM 	auclnt_pollwakeup(c, POLLOUT);
19129484Sgarrett.damore@Sun.COM }
19139484Sgarrett.damore@Sun.COM 
19149484Sgarrett.damore@Sun.COM static void
oss_input(audio_client_t * c)19159484Sgarrett.damore@Sun.COM oss_input(audio_client_t *c)
19169484Sgarrett.damore@Sun.COM {
19179484Sgarrett.damore@Sun.COM 	auclnt_pollwakeup(c, POLLIN | POLLRDNORM);
19189484Sgarrett.damore@Sun.COM }
19199484Sgarrett.damore@Sun.COM 
19209484Sgarrett.damore@Sun.COM static int
ossmix_open(audio_client_t * c,int oflag)19219484Sgarrett.damore@Sun.COM ossmix_open(audio_client_t *c, int oflag)
19229484Sgarrett.damore@Sun.COM {
19239484Sgarrett.damore@Sun.COM 	int		rv;
19249484Sgarrett.damore@Sun.COM 	ossclient_t	*sc;
19259484Sgarrett.damore@Sun.COM 	ossdev_t	*odev;
19269484Sgarrett.damore@Sun.COM 
19279484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(oflag));
19289484Sgarrett.damore@Sun.COM 
1929*12165Sgdamore@opensolaris.org 	if ((rv = auclnt_open(c, 0)) != 0) {
19309484Sgarrett.damore@Sun.COM 		return (rv);
19319484Sgarrett.damore@Sun.COM 	}
19329484Sgarrett.damore@Sun.COM 
19339484Sgarrett.damore@Sun.COM 	if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) {
19349484Sgarrett.damore@Sun.COM 		return (ENOMEM);
19359484Sgarrett.damore@Sun.COM 	}
19369484Sgarrett.damore@Sun.COM 	sc->o_ss_sz = 8192;
19379484Sgarrett.damore@Sun.COM 	if ((sc->o_ss_buf = kmem_zalloc(sc->o_ss_sz, KM_NOSLEEP)) == NULL) {
19389484Sgarrett.damore@Sun.COM 		kmem_free(sc, sizeof (*sc));
19399484Sgarrett.damore@Sun.COM 		return (ENOMEM);
19409484Sgarrett.damore@Sun.COM 	}
19419484Sgarrett.damore@Sun.COM 	auclnt_set_private(c, sc);
19429484Sgarrett.damore@Sun.COM 
19439484Sgarrett.damore@Sun.COM 	odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP);
19449484Sgarrett.damore@Sun.COM 
19459484Sgarrett.damore@Sun.COM 	/* set a couple of common fields */
19469484Sgarrett.damore@Sun.COM 	sc->o_client = c;
19479484Sgarrett.damore@Sun.COM 	sc->o_ossdev = odev;
19489484Sgarrett.damore@Sun.COM 
19499484Sgarrett.damore@Sun.COM 	return (rv);
19509484Sgarrett.damore@Sun.COM }
19519484Sgarrett.damore@Sun.COM 
19529484Sgarrett.damore@Sun.COM static void
ossmix_close(audio_client_t * c)19539484Sgarrett.damore@Sun.COM ossmix_close(audio_client_t *c)
19549484Sgarrett.damore@Sun.COM {
19559484Sgarrett.damore@Sun.COM 	ossclient_t	*sc;
19569484Sgarrett.damore@Sun.COM 
19579484Sgarrett.damore@Sun.COM 	sc = auclnt_get_private(c);
19589484Sgarrett.damore@Sun.COM 
19599484Sgarrett.damore@Sun.COM 	kmem_free(sc->o_ss_buf, sc->o_ss_sz);
19609484Sgarrett.damore@Sun.COM 	kmem_free(sc, sizeof (*sc));
19619484Sgarrett.damore@Sun.COM 
19629484Sgarrett.damore@Sun.COM 	auclnt_close(c);
19639484Sgarrett.damore@Sun.COM }
19649484Sgarrett.damore@Sun.COM 
19659484Sgarrett.damore@Sun.COM static int
sndctl_mix_nrext(audio_client_t * c,int * ncp)19669484Sgarrett.damore@Sun.COM sndctl_mix_nrext(audio_client_t *c, int *ncp)
19679484Sgarrett.damore@Sun.COM {
19689484Sgarrett.damore@Sun.COM 	audio_dev_t	*d;
19699484Sgarrett.damore@Sun.COM 	ossdev_t	*odev;
19709484Sgarrett.damore@Sun.COM 
19719484Sgarrett.damore@Sun.COM 	d = auclnt_get_dev(c);
19729484Sgarrett.damore@Sun.COM 
19739484Sgarrett.damore@Sun.COM 	if ((*ncp != -1) && (*ncp != (auclnt_get_dev_index(d) - 1))) {
19749484Sgarrett.damore@Sun.COM 		return (ENXIO);
19759484Sgarrett.damore@Sun.COM 	}
19769484Sgarrett.damore@Sun.COM 
19779484Sgarrett.damore@Sun.COM 	if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) {
19789484Sgarrett.damore@Sun.COM 		return (EINVAL);
19799484Sgarrett.damore@Sun.COM 	}
19809484Sgarrett.damore@Sun.COM 
19819484Sgarrett.damore@Sun.COM 	*ncp = odev->d_nctrl;
19829484Sgarrett.damore@Sun.COM 
19839484Sgarrett.damore@Sun.COM 	return (0);
19849484Sgarrett.damore@Sun.COM }
19859484Sgarrett.damore@Sun.COM 
19869484Sgarrett.damore@Sun.COM static int
sndctl_mix_extinfo(audio_client_t * c,oss_mixext * pext)19879484Sgarrett.damore@Sun.COM sndctl_mix_extinfo(audio_client_t *c, oss_mixext *pext)
19889484Sgarrett.damore@Sun.COM {
19899484Sgarrett.damore@Sun.COM 	audio_dev_t		*d;
19909484Sgarrett.damore@Sun.COM 	ossdev_t		*odev;
19919484Sgarrett.damore@Sun.COM 	int			rv = 0;
19929484Sgarrett.damore@Sun.COM 	int			dev;
19939484Sgarrett.damore@Sun.COM 
19949484Sgarrett.damore@Sun.COM 	d = auclnt_get_dev(c);
19959484Sgarrett.damore@Sun.COM 
19969484Sgarrett.damore@Sun.COM 	if (((dev = pext->dev) != -1) && (dev != (auclnt_get_dev_index(d) - 1)))
19979484Sgarrett.damore@Sun.COM 		return (ENXIO);
19989484Sgarrett.damore@Sun.COM 
19999484Sgarrett.damore@Sun.COM 	if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
20009484Sgarrett.damore@Sun.COM 	    (pext->ctrl >= odev->d_nctrl)) {
20019484Sgarrett.damore@Sun.COM 		return (EINVAL);
20029484Sgarrett.damore@Sun.COM 	}
20039484Sgarrett.damore@Sun.COM 
20049484Sgarrett.damore@Sun.COM 	bcopy(&odev->d_exts[pext->ctrl], pext, sizeof (*pext));
20059484Sgarrett.damore@Sun.COM 	pext->enumbit = 0;
20069484Sgarrett.damore@Sun.COM 	pext->dev = dev;
20079484Sgarrett.damore@Sun.COM 
20089484Sgarrett.damore@Sun.COM 	return (rv);
20099484Sgarrett.damore@Sun.COM }
20109484Sgarrett.damore@Sun.COM 
20119484Sgarrett.damore@Sun.COM static int
sndctl_mix_enuminfo(audio_client_t * c,oss_mixer_enuminfo * ei)20129484Sgarrett.damore@Sun.COM sndctl_mix_enuminfo(audio_client_t *c, oss_mixer_enuminfo *ei)
20139484Sgarrett.damore@Sun.COM {
20149484Sgarrett.damore@Sun.COM 	audio_dev_t		*d;
20159484Sgarrett.damore@Sun.COM 	audio_ctrl_desc_t	desc;
20169484Sgarrett.damore@Sun.COM 	audio_ctrl_t		*ctrl;
20179484Sgarrett.damore@Sun.COM 	ossdev_t		*odev;
20189484Sgarrett.damore@Sun.COM 	uint64_t		mask;
20199484Sgarrett.damore@Sun.COM 	int			bit;
20209484Sgarrett.damore@Sun.COM 	ushort_t		nxt;
20219484Sgarrett.damore@Sun.COM 
20229484Sgarrett.damore@Sun.COM 	d = auclnt_get_dev(c);
20239484Sgarrett.damore@Sun.COM 
20249484Sgarrett.damore@Sun.COM 	if ((ei->dev != -1) && (ei->dev != (auclnt_get_dev_index(d) - 1)))
20259484Sgarrett.damore@Sun.COM 		return (ENXIO);
20269484Sgarrett.damore@Sun.COM 
20279484Sgarrett.damore@Sun.COM 	if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
20289484Sgarrett.damore@Sun.COM 	    (ei->ctrl >= odev->d_nctrl) ||
20299484Sgarrett.damore@Sun.COM 	    (odev->d_exts[ei->ctrl].type != MIXT_ENUM) ||
20309484Sgarrett.damore@Sun.COM 	    ((ctrl = odev->d_ctrls[ei->ctrl]) == NULL) ||
20319484Sgarrett.damore@Sun.COM 	    (auclnt_control_describe(ctrl, &desc) != 0)) {
20329484Sgarrett.damore@Sun.COM 		return (EINVAL);
20339484Sgarrett.damore@Sun.COM 	}
20349484Sgarrett.damore@Sun.COM 
20359484Sgarrett.damore@Sun.COM 	mask = desc.acd_maxvalue;
20369484Sgarrett.damore@Sun.COM 	bit = 0;
20379484Sgarrett.damore@Sun.COM 	nxt = 0;
20389484Sgarrett.damore@Sun.COM 	ei->nvalues = 0;
20399484Sgarrett.damore@Sun.COM 	bzero(ei->strings, sizeof (ei->strings));
20409484Sgarrett.damore@Sun.COM 	bzero(ei->strindex, sizeof (ei->strindex));
20419484Sgarrett.damore@Sun.COM 
20429484Sgarrett.damore@Sun.COM 	while (mask) {
20439484Sgarrett.damore@Sun.COM 		const char *name = desc.acd_enum[bit];
20449484Sgarrett.damore@Sun.COM 		nxt = oss_set_enum(ei, nxt, name ? name : "");
20459484Sgarrett.damore@Sun.COM 		mask >>= 1;
20469484Sgarrett.damore@Sun.COM 		bit++;
20479484Sgarrett.damore@Sun.COM 	}
20489484Sgarrett.damore@Sun.COM 
20499484Sgarrett.damore@Sun.COM 	return (0);
20509484Sgarrett.damore@Sun.COM }
20519484Sgarrett.damore@Sun.COM 
20529484Sgarrett.damore@Sun.COM static int
sndctl_mix_read(audio_client_t * c,oss_mixer_value * vr)20539484Sgarrett.damore@Sun.COM sndctl_mix_read(audio_client_t *c, oss_mixer_value *vr)
20549484Sgarrett.damore@Sun.COM {
20559484Sgarrett.damore@Sun.COM 	int			rv;
20569484Sgarrett.damore@Sun.COM 	uint64_t		v;
20579484Sgarrett.damore@Sun.COM 	audio_dev_t		*d;
20589484Sgarrett.damore@Sun.COM 	audio_ctrl_t		*ctrl;
20599484Sgarrett.damore@Sun.COM 	ossdev_t		*odev;
20609484Sgarrett.damore@Sun.COM 
20619484Sgarrett.damore@Sun.COM 	d = auclnt_get_dev(c);
20629484Sgarrett.damore@Sun.COM 
20639484Sgarrett.damore@Sun.COM 	if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1)))
20649484Sgarrett.damore@Sun.COM 		return (ENXIO);
20659484Sgarrett.damore@Sun.COM 
20669484Sgarrett.damore@Sun.COM 	if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
20679484Sgarrett.damore@Sun.COM 	    (vr->ctrl >= odev->d_nctrl) ||
20689484Sgarrett.damore@Sun.COM 	    ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) {
20699484Sgarrett.damore@Sun.COM 		return (EINVAL);
20709484Sgarrett.damore@Sun.COM 	}
20719484Sgarrett.damore@Sun.COM 	if ((rv = auclnt_control_read(ctrl, &v)) == 0) {
20729484Sgarrett.damore@Sun.COM 		switch (odev->d_exts[vr->ctrl].type) {
20739484Sgarrett.damore@Sun.COM 		case MIXT_ENUM:
20749484Sgarrett.damore@Sun.COM 			/* translate this from an enum style bit mask */
20759484Sgarrett.damore@Sun.COM 			vr->value = ddi_ffs((unsigned long)v) - 1;
20769484Sgarrett.damore@Sun.COM 			break;
20779484Sgarrett.damore@Sun.COM 		case MIXT_STEREOSLIDER:
20789484Sgarrett.damore@Sun.COM 			vr->value = (int)ddi_swap16(v & 0xffff);
20799484Sgarrett.damore@Sun.COM 			break;
20809484Sgarrett.damore@Sun.COM 		case MIXT_MONOSLIDER:
20819484Sgarrett.damore@Sun.COM 			vr->value = (int)(v | (v << 8));
20829484Sgarrett.damore@Sun.COM 			break;
20839484Sgarrett.damore@Sun.COM 		case MIXT_ONOFF:
20849484Sgarrett.damore@Sun.COM 			/* this could be simple, or could be part of a multi */
20859484Sgarrett.damore@Sun.COM 			if (odev->d_exts[vr->ctrl].enumbit >= 0) {
20869484Sgarrett.damore@Sun.COM 				uint64_t mask;
20879484Sgarrett.damore@Sun.COM 				mask = 1;
20889484Sgarrett.damore@Sun.COM 				mask <<= (odev->d_exts[vr->ctrl].enumbit);
20899484Sgarrett.damore@Sun.COM 				vr->value = (v & mask) ? 1 : 0;
20909484Sgarrett.damore@Sun.COM 			} else {
20919484Sgarrett.damore@Sun.COM 				vr->value = v ? 1 : 0;
20929484Sgarrett.damore@Sun.COM 			}
20939484Sgarrett.damore@Sun.COM 			break;
20949484Sgarrett.damore@Sun.COM 
20959484Sgarrett.damore@Sun.COM 		default:
20969484Sgarrett.damore@Sun.COM 			vr->value = (int)v;
20979484Sgarrett.damore@Sun.COM 			break;
20989484Sgarrett.damore@Sun.COM 		}
20999484Sgarrett.damore@Sun.COM 	}
21009484Sgarrett.damore@Sun.COM 
21019484Sgarrett.damore@Sun.COM 	return (rv);
21029484Sgarrett.damore@Sun.COM }
21039484Sgarrett.damore@Sun.COM 
21049484Sgarrett.damore@Sun.COM static int
sndctl_mix_write(audio_client_t * c,oss_mixer_value * vr)21059484Sgarrett.damore@Sun.COM sndctl_mix_write(audio_client_t *c, oss_mixer_value *vr)
21069484Sgarrett.damore@Sun.COM {
21079484Sgarrett.damore@Sun.COM 	int			rv;
21089484Sgarrett.damore@Sun.COM 	uint64_t		v;
21099484Sgarrett.damore@Sun.COM 	audio_dev_t		*d;
21109484Sgarrett.damore@Sun.COM 	audio_ctrl_t		*ctrl;
21119484Sgarrett.damore@Sun.COM 	ossdev_t		*odev;
21129484Sgarrett.damore@Sun.COM 
21139484Sgarrett.damore@Sun.COM 	d = auclnt_get_dev(c);
21149484Sgarrett.damore@Sun.COM 
21159484Sgarrett.damore@Sun.COM 	if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1)))
21169484Sgarrett.damore@Sun.COM 		return (ENXIO);
21179484Sgarrett.damore@Sun.COM 
21189484Sgarrett.damore@Sun.COM 	if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
21199484Sgarrett.damore@Sun.COM 	    (vr->ctrl >= odev->d_nctrl) ||
21209484Sgarrett.damore@Sun.COM 	    ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) {
21219484Sgarrett.damore@Sun.COM 		return (EINVAL);
21229484Sgarrett.damore@Sun.COM 	}
21239484Sgarrett.damore@Sun.COM 
21249484Sgarrett.damore@Sun.COM 	switch (odev->d_exts[vr->ctrl].type) {
21259484Sgarrett.damore@Sun.COM 	case MIXT_ONOFF:
21269484Sgarrett.damore@Sun.COM 		/* this could be standalone, or it could be part of a multi */
21279484Sgarrett.damore@Sun.COM 		if (odev->d_exts[vr->ctrl].enumbit >= 0) {
21289484Sgarrett.damore@Sun.COM 			uint64_t mask;
21299484Sgarrett.damore@Sun.COM 			if ((rv = auclnt_control_read(ctrl, &v)) != 0) {
21309484Sgarrett.damore@Sun.COM 				return (EINVAL);
21319484Sgarrett.damore@Sun.COM 			}
21329484Sgarrett.damore@Sun.COM 			mask = 1;
21339484Sgarrett.damore@Sun.COM 			mask <<= (odev->d_exts[vr->ctrl].enumbit);
21349484Sgarrett.damore@Sun.COM 			if (vr->value) {
21359484Sgarrett.damore@Sun.COM 				v |= mask;
21369484Sgarrett.damore@Sun.COM 			} else {
21379484Sgarrett.damore@Sun.COM 				v &= ~mask;
21389484Sgarrett.damore@Sun.COM 			}
21399484Sgarrett.damore@Sun.COM 		} else {
21409484Sgarrett.damore@Sun.COM 			v = vr->value;
21419484Sgarrett.damore@Sun.COM 		}
21429484Sgarrett.damore@Sun.COM 		break;
21439484Sgarrett.damore@Sun.COM 	case MIXT_ENUM:
21449484Sgarrett.damore@Sun.COM 		/* translate this to an enum style bit mask */
21459484Sgarrett.damore@Sun.COM 		v = 1U << vr->value;
21469484Sgarrett.damore@Sun.COM 		break;
21479484Sgarrett.damore@Sun.COM 	case MIXT_MONOSLIDER:
21489484Sgarrett.damore@Sun.COM 		/* mask off high order bits */
21499484Sgarrett.damore@Sun.COM 		v = vr->value & 0xff;
21509484Sgarrett.damore@Sun.COM 		break;
21519484Sgarrett.damore@Sun.COM 	case MIXT_STEREOSLIDER:
21529484Sgarrett.damore@Sun.COM 		/* OSS uses reverse byte ordering */
21539484Sgarrett.damore@Sun.COM 		v = vr->value;
21549484Sgarrett.damore@Sun.COM 		v = ddi_swap16(vr->value & 0xffff);
21559484Sgarrett.damore@Sun.COM 		break;
21569484Sgarrett.damore@Sun.COM 	default:
21579484Sgarrett.damore@Sun.COM 		v = vr->value;
21589484Sgarrett.damore@Sun.COM 	}
21599484Sgarrett.damore@Sun.COM 	rv = auclnt_control_write(ctrl, v);
21609484Sgarrett.damore@Sun.COM 
21619484Sgarrett.damore@Sun.COM 	return (rv);
21629484Sgarrett.damore@Sun.COM }
21639484Sgarrett.damore@Sun.COM 
21649484Sgarrett.damore@Sun.COM static int
sndctl_mix_nrmix(audio_client_t * c,int * nmixp)21659484Sgarrett.damore@Sun.COM sndctl_mix_nrmix(audio_client_t *c, int *nmixp)
21669484Sgarrett.damore@Sun.COM {
21679484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
21689484Sgarrett.damore@Sun.COM 	*nmixp = oss_cnt_devs() - 1;
21699484Sgarrett.damore@Sun.COM 	return (0);
21709484Sgarrett.damore@Sun.COM }
21719484Sgarrett.damore@Sun.COM 
21729484Sgarrett.damore@Sun.COM static int
ossmix_ioctl(audio_client_t * c,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)21739484Sgarrett.damore@Sun.COM ossmix_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp,
21749484Sgarrett.damore@Sun.COM     int *rvalp)
21759484Sgarrett.damore@Sun.COM {
21769484Sgarrett.damore@Sun.COM 	int	sz;
21779484Sgarrett.damore@Sun.COM 	void	*data;
21789484Sgarrett.damore@Sun.COM 	int	rv = 0;
21799484Sgarrett.damore@Sun.COM 
21809484Sgarrett.damore@Sun.COM 	sz = OSSIOC_GETSZ(cmd);
21819484Sgarrett.damore@Sun.COM 
21829484Sgarrett.damore@Sun.COM 	if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) {
21839484Sgarrett.damore@Sun.COM 		if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) {
21849484Sgarrett.damore@Sun.COM 			return (ENOMEM);
21859484Sgarrett.damore@Sun.COM 		}
21869484Sgarrett.damore@Sun.COM 	} else {
21879484Sgarrett.damore@Sun.COM 		sz = 0;
21889484Sgarrett.damore@Sun.COM 	}
21899484Sgarrett.damore@Sun.COM 
21909484Sgarrett.damore@Sun.COM 	if (cmd & OSSIOC_IN) {
21919484Sgarrett.damore@Sun.COM 		if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) {
21929484Sgarrett.damore@Sun.COM 			goto done;
21939484Sgarrett.damore@Sun.COM 		}
21949484Sgarrett.damore@Sun.COM 	}
21959484Sgarrett.damore@Sun.COM 
21969484Sgarrett.damore@Sun.COM 	switch (cmd) {
21979484Sgarrett.damore@Sun.COM 		/*
21989484Sgarrett.damore@Sun.COM 		 * Mixer specific ioctls
21999484Sgarrett.damore@Sun.COM 		 */
22009484Sgarrett.damore@Sun.COM 	case SNDCTL_MIX_NREXT:
22019484Sgarrett.damore@Sun.COM 		rv = sndctl_mix_nrext(c, (int *)data);
22029484Sgarrett.damore@Sun.COM 		break;
22039484Sgarrett.damore@Sun.COM 	case SNDCTL_MIX_EXTINFO:
22049484Sgarrett.damore@Sun.COM 		rv = sndctl_mix_extinfo(c, (oss_mixext *)data);
22059484Sgarrett.damore@Sun.COM 		break;
22069484Sgarrett.damore@Sun.COM 	case SNDCTL_MIX_ENUMINFO:
22079484Sgarrett.damore@Sun.COM 		rv = sndctl_mix_enuminfo(c, (oss_mixer_enuminfo *)data);
22089484Sgarrett.damore@Sun.COM 		break;
22099484Sgarrett.damore@Sun.COM 	case SNDCTL_MIX_READ:
22109484Sgarrett.damore@Sun.COM 		rv = sndctl_mix_read(c, (oss_mixer_value *)data);
22119484Sgarrett.damore@Sun.COM 		break;
22129484Sgarrett.damore@Sun.COM 	case SNDCTL_MIX_WRITE:
22139484Sgarrett.damore@Sun.COM 		rv = sndctl_mix_write(c, (oss_mixer_value *)data);
22149484Sgarrett.damore@Sun.COM 		break;
22159484Sgarrett.damore@Sun.COM 	case SNDCTL_MIX_NRMIX:
22169484Sgarrett.damore@Sun.COM 		rv = sndctl_mix_nrmix(c, (int *)data);
22179484Sgarrett.damore@Sun.COM 		break;
22189484Sgarrett.damore@Sun.COM 
22199484Sgarrett.damore@Sun.COM 		/*
22209484Sgarrett.damore@Sun.COM 		 * Legacy ioctls.  These are treated as soft values only,
22219484Sgarrett.damore@Sun.COM 		 * and do not affect global hardware state.  For use by
22229484Sgarrett.damore@Sun.COM 		 * legacy DSP applications.
22239484Sgarrett.damore@Sun.COM 		 */
22249484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_VOLUME:
22259484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_PCM:
22269484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_OGAIN:
22279484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getplayvol(c, (int *)data);
22289484Sgarrett.damore@Sun.COM 		break;
22299484Sgarrett.damore@Sun.COM 
22309484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_VOLUME:
22319484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_PCM:
22329484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_OGAIN:
22339484Sgarrett.damore@Sun.COM 		rv = sound_mixer_write_ogain(c, (int *)data);
22349484Sgarrett.damore@Sun.COM 		break;
22359484Sgarrett.damore@Sun.COM 
22369484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_RECGAIN:
22379484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_RECLEV:
22389484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_IGAIN:
22399484Sgarrett.damore@Sun.COM 		rv = sndctl_dsp_getrecvol(c, (int *)data);
22409484Sgarrett.damore@Sun.COM 		break;
22419484Sgarrett.damore@Sun.COM 
22429484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_RECGAIN:
22439484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_RECLEV:
22449484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_IGAIN:
22459484Sgarrett.damore@Sun.COM 		rv = sound_mixer_write_igain(c, (int *)data);
22469484Sgarrett.damore@Sun.COM 		break;
22479484Sgarrett.damore@Sun.COM 
22489484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_RECSRC:
22499484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_RECSRC:
22509484Sgarrett.damore@Sun.COM 		rv = sound_mixer_read_recsrc(c, (int *)data);
22519484Sgarrett.damore@Sun.COM 		break;
22529484Sgarrett.damore@Sun.COM 
22539484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_DEVMASK:
22549484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_STEREODEVS:
22559484Sgarrett.damore@Sun.COM 		rv = sound_mixer_read_devmask(c, (int *)data);
22569484Sgarrett.damore@Sun.COM 		break;
22579484Sgarrett.damore@Sun.COM 
22589484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_RECMASK:
22599484Sgarrett.damore@Sun.COM 		rv = sound_mixer_read_recmask(c, (int *)data);
22609484Sgarrett.damore@Sun.COM 		break;
22619484Sgarrett.damore@Sun.COM 
226210184Sgdamore@opensolaris.org 	case SOUND_MIXER_READ_CAPS:
226310184Sgdamore@opensolaris.org 		rv = sound_mixer_read_caps(c, (int *)data);
226410184Sgdamore@opensolaris.org 		break;
226510184Sgdamore@opensolaris.org 
22669484Sgarrett.damore@Sun.COM 		/*
22679484Sgarrett.damore@Sun.COM 		 * Common ioctls shared with DSP
22689484Sgarrett.damore@Sun.COM 		 */
22699484Sgarrett.damore@Sun.COM 	case OSS_GETVERSION:
22709484Sgarrett.damore@Sun.COM 		rv = oss_getversion((int *)data);
22719484Sgarrett.damore@Sun.COM 		break;
22729484Sgarrett.damore@Sun.COM 
22739484Sgarrett.damore@Sun.COM 	case SNDCTL_CARDINFO:
22749484Sgarrett.damore@Sun.COM 		rv = sndctl_cardinfo(c, (oss_card_info *)data);
22759484Sgarrett.damore@Sun.COM 		break;
22769484Sgarrett.damore@Sun.COM 
22779484Sgarrett.damore@Sun.COM 	case SNDCTL_ENGINEINFO:
22789484Sgarrett.damore@Sun.COM 	case SNDCTL_AUDIOINFO:
22799484Sgarrett.damore@Sun.COM 	case SNDCTL_AUDIOINFO_EX:
22809484Sgarrett.damore@Sun.COM 		rv = sndctl_audioinfo(c, (oss_audioinfo *)data);
22819484Sgarrett.damore@Sun.COM 		break;
22829484Sgarrett.damore@Sun.COM 
22839484Sgarrett.damore@Sun.COM 	case SNDCTL_SYSINFO:
22849484Sgarrett.damore@Sun.COM 		rv = sndctl_sysinfo((oss_sysinfo *)data);
22859484Sgarrett.damore@Sun.COM 		break;
22869484Sgarrett.damore@Sun.COM 
22879484Sgarrett.damore@Sun.COM 	case SNDCTL_MIXERINFO:
22889484Sgarrett.damore@Sun.COM 		rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data);
22899484Sgarrett.damore@Sun.COM 		break;
22909484Sgarrett.damore@Sun.COM 
22919484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_INFO:
22929484Sgarrett.damore@Sun.COM 		rv = sound_mixer_info(c, (mixer_info *)data);
22939484Sgarrett.damore@Sun.COM 		break;
22949484Sgarrett.damore@Sun.COM 
22959484Sgarrett.damore@Sun.COM 	case SNDCTL_MIX_DESCRIPTION:	/* NOT SUPPORTED: tooltip */
22969484Sgarrett.damore@Sun.COM 		rv = EIO;	/* OSS returns EIO for this one */
22979484Sgarrett.damore@Sun.COM 		break;
22989484Sgarrett.damore@Sun.COM 
22999484Sgarrett.damore@Sun.COM 		/*
23009484Sgarrett.damore@Sun.COM 		 * Special implementation-private ioctls.
23019484Sgarrett.damore@Sun.COM 		 */
23029484Sgarrett.damore@Sun.COM 	case SNDCTL_SUN_SEND_NUMBER:
23039484Sgarrett.damore@Sun.COM 		rv = sndctl_sun_send_number(c, (int *)data, credp);
23049484Sgarrett.damore@Sun.COM 		break;
23059484Sgarrett.damore@Sun.COM 
23069484Sgarrett.damore@Sun.COM 		/*
23079484Sgarrett.damore@Sun.COM 		 * Legacy ioctls we don't support.
23089484Sgarrett.damore@Sun.COM 		 */
23099484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_MONGAIN:
23109484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_MONGAIN:
23119484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_BASS:
23129484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_TREBLE:
23139484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_SPEAKER:
23149484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_LINE:
23159484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_MIC:
23169484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_CD:
23179484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_IMIX:
23189484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_ALTPCM:
23199484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_SYNTH:
23209484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_LINE1:
23219484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_LINE2:
23229484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_READ_LINE3:
23239484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_BASS:
23249484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_TREBLE:
23259484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_SPEAKER:
23269484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_LINE:
23279484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_MIC:
23289484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_CD:
23299484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_IMIX:
23309484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_ALTPCM:
23319484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_SYNTH:
23329484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_LINE1:
23339484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_LINE2:
23349484Sgarrett.damore@Sun.COM 	case SOUND_MIXER_WRITE_LINE3:
23359484Sgarrett.damore@Sun.COM 		/*
23369484Sgarrett.damore@Sun.COM 		 * Additional ioctls we *could* support, but don't.
23379484Sgarrett.damore@Sun.COM 		 */
23389484Sgarrett.damore@Sun.COM 	case SNDCTL_SETSONG:
23399484Sgarrett.damore@Sun.COM 	case SNDCTL_SETLABEL:
23409484Sgarrett.damore@Sun.COM 	case SNDCTL_GETSONG:
23419484Sgarrett.damore@Sun.COM 	case SNDCTL_GETLABEL:
23429484Sgarrett.damore@Sun.COM 	case SNDCTL_MIDIINFO:
23439484Sgarrett.damore@Sun.COM 	case SNDCTL_SETNAME:
23449484Sgarrett.damore@Sun.COM 	default:
23459484Sgarrett.damore@Sun.COM 		rv = EINVAL;
23469484Sgarrett.damore@Sun.COM 		break;
23479484Sgarrett.damore@Sun.COM 	}
23489484Sgarrett.damore@Sun.COM 
23499484Sgarrett.damore@Sun.COM 	if ((rv == 0) && (cmd & OSSIOC_OUT)) {
23509484Sgarrett.damore@Sun.COM 		rv = ddi_copyout(data, (void *)arg, sz, mode);
23519484Sgarrett.damore@Sun.COM 	}
23529484Sgarrett.damore@Sun.COM 	if (rv == 0) {
23539484Sgarrett.damore@Sun.COM 		*rvalp = 0;
23549484Sgarrett.damore@Sun.COM 	}
23559484Sgarrett.damore@Sun.COM 
23569484Sgarrett.damore@Sun.COM done:
23579484Sgarrett.damore@Sun.COM 	if (sz) {
23589484Sgarrett.damore@Sun.COM 		kmem_free(data, sz);
23599484Sgarrett.damore@Sun.COM 	}
23609484Sgarrett.damore@Sun.COM 	return (rv);
23619484Sgarrett.damore@Sun.COM }
23629484Sgarrett.damore@Sun.COM 
23639484Sgarrett.damore@Sun.COM static void *
oss_dev_init(audio_dev_t * dev)23649484Sgarrett.damore@Sun.COM oss_dev_init(audio_dev_t *dev)
23659484Sgarrett.damore@Sun.COM {
23669484Sgarrett.damore@Sun.COM 	ossdev_t	*odev;
23679484Sgarrett.damore@Sun.COM 
23689484Sgarrett.damore@Sun.COM 	odev = kmem_zalloc(sizeof (*odev), KM_SLEEP);
23699484Sgarrett.damore@Sun.COM 	odev->d_dev = dev;
23709484Sgarrett.damore@Sun.COM 
23719484Sgarrett.damore@Sun.COM 	mutex_init(&odev->d_mx, NULL, MUTEX_DRIVER, NULL);
23729484Sgarrett.damore@Sun.COM 	cv_init(&odev->d_cv, NULL, CV_DRIVER, NULL);
23739484Sgarrett.damore@Sun.COM 	oss_alloc_controls(odev);
23749484Sgarrett.damore@Sun.COM 
23759484Sgarrett.damore@Sun.COM 	return (odev);
23769484Sgarrett.damore@Sun.COM }
23779484Sgarrett.damore@Sun.COM 
23789484Sgarrett.damore@Sun.COM static void
oss_dev_fini(void * arg)23799484Sgarrett.damore@Sun.COM oss_dev_fini(void *arg)
23809484Sgarrett.damore@Sun.COM {
23819484Sgarrett.damore@Sun.COM 	ossdev_t	*odev = arg;
23829484Sgarrett.damore@Sun.COM 
23839484Sgarrett.damore@Sun.COM 	if (odev != NULL) {
23849484Sgarrett.damore@Sun.COM 		oss_free_controls(odev);
23859484Sgarrett.damore@Sun.COM 		mutex_destroy(&odev->d_mx);
23869484Sgarrett.damore@Sun.COM 		cv_destroy(&odev->d_cv);
23879484Sgarrett.damore@Sun.COM 		kmem_free(odev, sizeof (*odev));
23889484Sgarrett.damore@Sun.COM 	}
23899484Sgarrett.damore@Sun.COM }
23909484Sgarrett.damore@Sun.COM 
23919484Sgarrett.damore@Sun.COM static void
sndstat_printf(ossclient_t * oc,const char * fmt,...)23929484Sgarrett.damore@Sun.COM sndstat_printf(ossclient_t *oc, const char *fmt, ...)
23939484Sgarrett.damore@Sun.COM {
23949484Sgarrett.damore@Sun.COM 	va_list	va;
23959484Sgarrett.damore@Sun.COM 
23969484Sgarrett.damore@Sun.COM 	va_start(va, fmt);
23979484Sgarrett.damore@Sun.COM 	(void) vsnprintf(oc->o_ss_buf + oc->o_ss_len,
23989484Sgarrett.damore@Sun.COM 	    oc->o_ss_sz - oc->o_ss_len, fmt, va);
23999484Sgarrett.damore@Sun.COM 	va_end(va);
24009484Sgarrett.damore@Sun.COM 	oc->o_ss_len = strlen(oc->o_ss_buf);
24019484Sgarrett.damore@Sun.COM }
24029484Sgarrett.damore@Sun.COM 
24039484Sgarrett.damore@Sun.COM static int
sndstat_dev_walker(audio_dev_t * d,void * arg)24049484Sgarrett.damore@Sun.COM sndstat_dev_walker(audio_dev_t *d, void *arg)
24059484Sgarrett.damore@Sun.COM {
24069484Sgarrett.damore@Sun.COM 	ossclient_t	*oc = arg;
24079484Sgarrett.damore@Sun.COM 	const char	*capstr;
24089484Sgarrett.damore@Sun.COM 	unsigned	cap;
24099484Sgarrett.damore@Sun.COM 
24109484Sgarrett.damore@Sun.COM 	cap = auclnt_get_dev_capab(d);
24119484Sgarrett.damore@Sun.COM 
24129484Sgarrett.damore@Sun.COM 	if (cap	& AUDIO_CLIENT_CAP_DUPLEX) {
24139484Sgarrett.damore@Sun.COM 		capstr = "DUPLEX";
24149484Sgarrett.damore@Sun.COM 	} else if ((cap & AUDIO_CLIENT_CAP_PLAY) &&
24159484Sgarrett.damore@Sun.COM 	    (cap & AUDIO_CLIENT_CAP_RECORD)) {
24169484Sgarrett.damore@Sun.COM 		capstr = "INPUT,OUTPUT";
24179484Sgarrett.damore@Sun.COM 	} else if (cap & AUDIO_CLIENT_CAP_PLAY) {
24189484Sgarrett.damore@Sun.COM 		capstr = "OUTPUT";
24199484Sgarrett.damore@Sun.COM 	} else if (cap & AUDIO_CLIENT_CAP_RECORD) {
24209484Sgarrett.damore@Sun.COM 		capstr = "INPUT";
24219484Sgarrett.damore@Sun.COM 	} else {
24229484Sgarrett.damore@Sun.COM 		capstr = NULL;
24239484Sgarrett.damore@Sun.COM 	}
24249484Sgarrett.damore@Sun.COM 
24259484Sgarrett.damore@Sun.COM 	if (capstr == NULL)
24269484Sgarrett.damore@Sun.COM 		return (AUDIO_WALK_CONTINUE);
24279484Sgarrett.damore@Sun.COM 
24289484Sgarrett.damore@Sun.COM 	sndstat_printf(oc, "%d: %s %s, %s (%s)\n",
24299484Sgarrett.damore@Sun.COM 	    auclnt_get_dev_number(d), auclnt_get_dev_name(d),
24309484Sgarrett.damore@Sun.COM 	    auclnt_get_dev_description(d), auclnt_get_dev_version(d), capstr);
24319484Sgarrett.damore@Sun.COM 
24329484Sgarrett.damore@Sun.COM 	return (AUDIO_WALK_CONTINUE);
24339484Sgarrett.damore@Sun.COM }
24349484Sgarrett.damore@Sun.COM 
24359484Sgarrett.damore@Sun.COM static int
sndstat_mixer_walker(audio_dev_t * d,void * arg)24369484Sgarrett.damore@Sun.COM sndstat_mixer_walker(audio_dev_t *d, void *arg)
24379484Sgarrett.damore@Sun.COM {
24389484Sgarrett.damore@Sun.COM 	ossclient_t	*oc = arg;
24399484Sgarrett.damore@Sun.COM 	unsigned	cap;
24409484Sgarrett.damore@Sun.COM 	void		*iter;
24419484Sgarrett.damore@Sun.COM 	const char	*info;
24429484Sgarrett.damore@Sun.COM 
24439484Sgarrett.damore@Sun.COM 	cap = auclnt_get_dev_capab(d);
24449484Sgarrett.damore@Sun.COM 
24459484Sgarrett.damore@Sun.COM 	if ((cap & (AUDIO_CLIENT_CAP_PLAY|AUDIO_CLIENT_CAP_RECORD)) == 0)
24469484Sgarrett.damore@Sun.COM 		return (AUDIO_WALK_CONTINUE);
24479484Sgarrett.damore@Sun.COM 
24489484Sgarrett.damore@Sun.COM 	sndstat_printf(oc, "%d: %s %s, %s\n",
24499484Sgarrett.damore@Sun.COM 	    auclnt_get_dev_number(d), auclnt_get_dev_name(d),
24509484Sgarrett.damore@Sun.COM 	    auclnt_get_dev_description(d), auclnt_get_dev_version(d));
24519484Sgarrett.damore@Sun.COM 	iter = NULL;
24529484Sgarrett.damore@Sun.COM 	while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) {
24539484Sgarrett.damore@Sun.COM 		sndstat_printf(oc, "\t%s\n", info);
24549484Sgarrett.damore@Sun.COM 	}
24559484Sgarrett.damore@Sun.COM 	return (AUDIO_WALK_CONTINUE);
24569484Sgarrett.damore@Sun.COM }
24579484Sgarrett.damore@Sun.COM 
24589484Sgarrett.damore@Sun.COM static int
ossmix_write(audio_client_t * c,struct uio * uio,cred_t * cr)24599484Sgarrett.damore@Sun.COM ossmix_write(audio_client_t *c, struct uio *uio, cred_t *cr)
24609484Sgarrett.damore@Sun.COM {
24619484Sgarrett.damore@Sun.COM 	/* write on sndstat is a no-op */
24629484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(c));
24639484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(uio));
24649484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(cr));
24659484Sgarrett.damore@Sun.COM 
24669484Sgarrett.damore@Sun.COM 	return (0);
24679484Sgarrett.damore@Sun.COM }
24689484Sgarrett.damore@Sun.COM 
24699484Sgarrett.damore@Sun.COM static int
ossmix_read(audio_client_t * c,struct uio * uio,cred_t * cr)24709484Sgarrett.damore@Sun.COM ossmix_read(audio_client_t *c, struct uio *uio, cred_t *cr)
24719484Sgarrett.damore@Sun.COM {
24729484Sgarrett.damore@Sun.COM 	ossclient_t	*oc;
24739484Sgarrett.damore@Sun.COM 	unsigned	n;
24749484Sgarrett.damore@Sun.COM 	int		rv;
24759484Sgarrett.damore@Sun.COM 
24769484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(cr));
24779484Sgarrett.damore@Sun.COM 
24789484Sgarrett.damore@Sun.COM 	if (uio->uio_resid == 0) {
24799484Sgarrett.damore@Sun.COM 		return (0);
24809484Sgarrett.damore@Sun.COM 	}
24819484Sgarrett.damore@Sun.COM 
24829484Sgarrett.damore@Sun.COM 	oc = auclnt_get_private(c);
24839484Sgarrett.damore@Sun.COM 
24849484Sgarrett.damore@Sun.COM 	mutex_enter(&oc->o_ss_lock);
24859484Sgarrett.damore@Sun.COM 
24869484Sgarrett.damore@Sun.COM 	if (oc->o_ss_off == 0) {
24879484Sgarrett.damore@Sun.COM 
24889484Sgarrett.damore@Sun.COM 		sndstat_printf(oc, "SunOS Audio Framework\n");
24899484Sgarrett.damore@Sun.COM 
24909484Sgarrett.damore@Sun.COM 		sndstat_printf(oc, "\nAudio Devices:\n");
24919484Sgarrett.damore@Sun.COM 		auclnt_walk_devs_by_number(sndstat_dev_walker, oc);
24929484Sgarrett.damore@Sun.COM 
24939484Sgarrett.damore@Sun.COM 		sndstat_printf(oc, "\nMixers:\n");
24949484Sgarrett.damore@Sun.COM 		auclnt_walk_devs_by_number(sndstat_mixer_walker, oc);
24959484Sgarrett.damore@Sun.COM 	}
24969484Sgarrett.damore@Sun.COM 
24979484Sgarrett.damore@Sun.COM 	/*
24989484Sgarrett.damore@Sun.COM 	 * For simplicity's sake, we implement a non-seekable device.  We could
24999484Sgarrett.damore@Sun.COM 	 * support seekability, but offsets would be rather meaningless between
25009484Sgarrett.damore@Sun.COM 	 * changes.
25019484Sgarrett.damore@Sun.COM 	 */
25029484Sgarrett.damore@Sun.COM 	n = min(uio->uio_resid, (oc->o_ss_len - oc->o_ss_off));
25039484Sgarrett.damore@Sun.COM 
25049484Sgarrett.damore@Sun.COM 	rv = uiomove(oc->o_ss_buf + oc->o_ss_off, n, UIO_READ, uio);
25059484Sgarrett.damore@Sun.COM 	if (rv != 0) {
25069484Sgarrett.damore@Sun.COM 		n = 0;
25079484Sgarrett.damore@Sun.COM 	}
25089484Sgarrett.damore@Sun.COM 	oc->o_ss_off += n;
25099484Sgarrett.damore@Sun.COM 
25109484Sgarrett.damore@Sun.COM 	if (n == 0) {
25119484Sgarrett.damore@Sun.COM 		/*
25129484Sgarrett.damore@Sun.COM 		 * end-of-file reached... clear the sndstat buffer so that
25139484Sgarrett.damore@Sun.COM 		 * subsequent reads will get the latest data.
25149484Sgarrett.damore@Sun.COM 		 */
25159484Sgarrett.damore@Sun.COM 		oc->o_ss_off = oc->o_ss_len = 0;
25169484Sgarrett.damore@Sun.COM 	}
25179484Sgarrett.damore@Sun.COM 	mutex_exit(&oc->o_ss_lock);
25189484Sgarrett.damore@Sun.COM 	return (rv);
25199484Sgarrett.damore@Sun.COM }
25209484Sgarrett.damore@Sun.COM 
25219484Sgarrett.damore@Sun.COM int
oss_read(audio_client_t * c,struct uio * uio,cred_t * cr)25229484Sgarrett.damore@Sun.COM oss_read(audio_client_t *c, struct uio *uio, cred_t *cr)
25239484Sgarrett.damore@Sun.COM {
25249484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(cr));
25259484Sgarrett.damore@Sun.COM 
25269484Sgarrett.damore@Sun.COM 	auclnt_clear_paused(auclnt_input_stream(c));
25279484Sgarrett.damore@Sun.COM 
25289484Sgarrett.damore@Sun.COM 	return (auclnt_read(c, uio));
25299484Sgarrett.damore@Sun.COM }
25309484Sgarrett.damore@Sun.COM 
25319484Sgarrett.damore@Sun.COM int
oss_write(audio_client_t * c,struct uio * uio,cred_t * cr)25329484Sgarrett.damore@Sun.COM oss_write(audio_client_t *c, struct uio *uio, cred_t *cr)
25339484Sgarrett.damore@Sun.COM {
25349484Sgarrett.damore@Sun.COM 	_NOTE(ARGUNUSED(cr));
25359484Sgarrett.damore@Sun.COM 
25369484Sgarrett.damore@Sun.COM 	auclnt_clear_paused(auclnt_output_stream(c));
25379484Sgarrett.damore@Sun.COM 
25389484Sgarrett.damore@Sun.COM 	return (auclnt_write(c, uio));
25399484Sgarrett.damore@Sun.COM }
25409484Sgarrett.damore@Sun.COM 
25419484Sgarrett.damore@Sun.COM int
oss_chpoll(audio_client_t * c,short events,int anyyet,short * reventsp,struct pollhead ** phpp)25429484Sgarrett.damore@Sun.COM oss_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp,
25439484Sgarrett.damore@Sun.COM     struct pollhead **phpp)
25449484Sgarrett.damore@Sun.COM {
25459484Sgarrett.damore@Sun.COM 	return (auclnt_chpoll(c, events, anyyet, reventsp, phpp));
25469484Sgarrett.damore@Sun.COM }
25479484Sgarrett.damore@Sun.COM 
25489484Sgarrett.damore@Sun.COM static struct audio_client_ops oss_ops = {
25499484Sgarrett.damore@Sun.COM 	"sound,dsp",
25509484Sgarrett.damore@Sun.COM 	oss_dev_init,
25519484Sgarrett.damore@Sun.COM 	oss_dev_fini,
25529484Sgarrett.damore@Sun.COM 	oss_open,
25539484Sgarrett.damore@Sun.COM 	oss_close,
25549484Sgarrett.damore@Sun.COM 	oss_read,
25559484Sgarrett.damore@Sun.COM 	oss_write,
25569484Sgarrett.damore@Sun.COM 	oss_ioctl,
25579484Sgarrett.damore@Sun.COM 	oss_chpoll,
25589484Sgarrett.damore@Sun.COM 	NULL,		/* mmap */
25599484Sgarrett.damore@Sun.COM 	oss_input,
25609484Sgarrett.damore@Sun.COM 	oss_output,
25619484Sgarrett.damore@Sun.COM 	NULL,		/* drain */
25629484Sgarrett.damore@Sun.COM };
25639484Sgarrett.damore@Sun.COM 
25649484Sgarrett.damore@Sun.COM static struct audio_client_ops ossmix_ops = {
25659484Sgarrett.damore@Sun.COM 	"sound,mixer",
25669484Sgarrett.damore@Sun.COM 	NULL,
25679484Sgarrett.damore@Sun.COM 	NULL,
25689484Sgarrett.damore@Sun.COM 	ossmix_open,
25699484Sgarrett.damore@Sun.COM 	ossmix_close,
25709484Sgarrett.damore@Sun.COM 	ossmix_read,
25719484Sgarrett.damore@Sun.COM 	ossmix_write,
25729484Sgarrett.damore@Sun.COM 	ossmix_ioctl,
25739484Sgarrett.damore@Sun.COM 	NULL,	/* chpoll */
25749484Sgarrett.damore@Sun.COM 	NULL,   /* mmap */
25759484Sgarrett.damore@Sun.COM 	NULL,	/* input */
25769484Sgarrett.damore@Sun.COM 	NULL,   /* output */
25779484Sgarrett.damore@Sun.COM 	NULL,	/* drain */
257810157Sgdamore@opensolaris.org 	NULL,	/* wput */
257910157Sgdamore@opensolaris.org 	NULL,	/* wsrv */
25809484Sgarrett.damore@Sun.COM };
25819484Sgarrett.damore@Sun.COM 
25829484Sgarrett.damore@Sun.COM /* nearly the same as ossxmix; different minor name helps devfsadm */
25839484Sgarrett.damore@Sun.COM static struct audio_client_ops sndstat_ops = {
25849484Sgarrett.damore@Sun.COM 	"sound,sndstat",
25859484Sgarrett.damore@Sun.COM 	NULL,	/* dev_init */
25869484Sgarrett.damore@Sun.COM 	NULL,	/* dev_fini */
25879484Sgarrett.damore@Sun.COM 	ossmix_open,
25889484Sgarrett.damore@Sun.COM 	ossmix_close,
25899484Sgarrett.damore@Sun.COM 	ossmix_read,
25909484Sgarrett.damore@Sun.COM 	ossmix_write,
25919484Sgarrett.damore@Sun.COM 	ossmix_ioctl,
25929484Sgarrett.damore@Sun.COM 	NULL,	/* chpoll */
25939484Sgarrett.damore@Sun.COM 	NULL,	/* mmap */
25949484Sgarrett.damore@Sun.COM 	NULL,	/* input */
25959484Sgarrett.damore@Sun.COM 	NULL,	/* output */
25969484Sgarrett.damore@Sun.COM 	NULL,	/* drain */
259710157Sgdamore@opensolaris.org 	NULL,	/* wput */
259810157Sgdamore@opensolaris.org 	NULL,	/* wsrv */
25999484Sgarrett.damore@Sun.COM };
26009484Sgarrett.damore@Sun.COM 
26019484Sgarrett.damore@Sun.COM void
auimpl_oss_init(void)26029484Sgarrett.damore@Sun.COM auimpl_oss_init(void)
26039484Sgarrett.damore@Sun.COM {
26049484Sgarrett.damore@Sun.COM 	auclnt_register_ops(AUDIO_MINOR_DSP, &oss_ops);
26059484Sgarrett.damore@Sun.COM 	auclnt_register_ops(AUDIO_MINOR_MIXER, &ossmix_ops);
26069484Sgarrett.damore@Sun.COM 	auclnt_register_ops(AUDIO_MINOR_SNDSTAT, &sndstat_ops);
26079484Sgarrett.damore@Sun.COM }
2608