xref: /illumos-gate/usr/src/uts/common/io/audio/impl/audio_oss.c (revision 104a37ccc1f0447ab5567644c98d5ed7266d3211)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/open.h>
28 #include <sys/errno.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/audio/audio_oss.h>
32 #include <sys/file.h>
33 #include <sys/note.h>
34 #include <sys/sysmacros.h>
35 #include <sys/list.h>
36 #include "audio_client.h"
37 
38 #define	OSS_FMT		AFMT_S16_LE
39 #define	OSS_RATE	48000
40 #define	OSS_CHANNELS	2
41 
42 typedef struct ossclient ossclient_t;
43 typedef struct ossdev ossdev_t;
44 
45 static const struct {
46 	int	oss;
47 	int	fmt;
48 } oss_formats[] = {
49 	{ AFMT_MU_LAW,		AUDIO_FORMAT_ULAW },
50 	{ AFMT_A_LAW,		AUDIO_FORMAT_ALAW },
51 	{ AFMT_U8,		AUDIO_FORMAT_U8 },
52 	{ AFMT_S8,		AUDIO_FORMAT_S8 },
53 	{ AFMT_S16_BE,		AUDIO_FORMAT_S16_BE },
54 	{ AFMT_S16_LE,		AUDIO_FORMAT_S16_LE },
55 	{ AFMT_U16_BE,		AUDIO_FORMAT_U16_BE },
56 	{ AFMT_U16_LE,		AUDIO_FORMAT_U16_LE },
57 	{ AFMT_S24_BE,		AUDIO_FORMAT_S24_BE },
58 	{ AFMT_S24_LE,		AUDIO_FORMAT_S24_LE },
59 	{ AFMT_S32_BE,		AUDIO_FORMAT_S32_BE },
60 	{ AFMT_S32_LE,		AUDIO_FORMAT_S32_LE },
61 	{ AFMT_S24_PACKED,	AUDIO_FORMAT_S24_PACKED },
62 	{ AFMT_AC3,		AUDIO_FORMAT_AC3 },
63 	{ AFMT_QUERY,		AUDIO_FORMAT_NONE }
64 };
65 
66 /* common structure shared between both mixer and dsp nodes */
67 struct ossclient {
68 	ossdev_t		*o_ossdev;
69 	audio_client_t		*o_client;
70 	/* sndstat */
71 	kmutex_t		o_ss_lock;
72 	char			*o_ss_buf;
73 	size_t			o_ss_len;
74 	size_t			o_ss_sz;
75 	size_t			o_ss_off;
76 };
77 
78 struct ossdev {
79 	audio_dev_t		*d_dev;
80 
81 	uint_t			d_modify_cnt;	/* flag apps of ctrl changes */
82 	uint_t			d_nctrl;	/* num actual controls */
83 	uint_t			d_nalloc;	/* num allocated controls */
84 	audio_ctrl_t		**d_ctrls;	/* array of control handles */
85 	oss_mixext		*d_exts;	/* array of mixer descs */
86 
87 	int			d_play_grp;
88 	int			d_rec_grp;
89 	int			d_mon_grp;
90 	int			d_misc_grp;
91 
92 	kmutex_t		d_mx;
93 	kcondvar_t		d_cv;
94 };
95 
96 static int
97 oss_cnt_controls(audio_ctrl_t *ctrl, void *arg)
98 {
99 	int			*pint = (int *)arg;
100 	int			cnt;
101 	audio_ctrl_desc_t	desc;
102 
103 	cnt = *pint;
104 	cnt++;
105 	*pint = cnt;
106 
107 	if (auclnt_control_describe(ctrl, &desc) != 0)
108 		return (AUDIO_WALK_CONTINUE);
109 
110 	if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) {
111 		for (uint64_t mask = desc.acd_maxvalue; mask; mask >>= 1) {
112 			if (mask & 1) {
113 				cnt++;
114 			}
115 		}
116 		*pint = cnt;
117 	}
118 
119 	return (AUDIO_WALK_CONTINUE);
120 }
121 
122 /*
123  * Add one entry to the OSS user control table to internal control
124  * helper table.
125  *
126  * This is used with auimpl_walk_controls. The table must be pre-
127  * allocated before it is walk'd. This includes the root and
128  * extended control markers!
129  */
130 static int
131 oss_add_control(audio_ctrl_t *ctrl, void *arg)
132 {
133 	ossdev_t		*odev = arg;
134 	audio_ctrl_desc_t	desc;
135 	oss_mixext		*ext;
136 	int			bit;
137 	uint64_t		mask;
138 	const char		*name;
139 	int			parent;
140 	int			flags;
141 	unsigned		scope;
142 
143 	if (auclnt_control_describe(ctrl, &desc))
144 		return (AUDIO_WALK_CONTINUE);
145 
146 	parent = 0;
147 
148 	/*
149 	 * Add appropriate group if not already done so.
150 	 */
151 	if (desc.acd_flags & AUDIO_CTRL_FLAG_PLAY) {
152 		if (!odev->d_play_grp) {
153 			ext = &odev->d_exts[odev->d_nctrl];
154 			ext->ctrl = odev->d_nctrl;
155 			ext->control_no = -1;
156 			ext->type = MIXT_GROUP;
157 			ext->desc = MIXEXT_SCOPE_OUTPUT;
158 			ext->timestamp = gethrtime();
159 			(void) snprintf(ext->id, sizeof (ext->id), "PLAYBACK");
160 			odev->d_play_grp = odev->d_nctrl;
161 			odev->d_nctrl++;
162 		}
163 		scope = MIXEXT_SCOPE_OUTPUT;
164 		parent = odev->d_play_grp;
165 	} else if (desc.acd_flags & AUDIO_CTRL_FLAG_REC) {
166 		if (!odev->d_rec_grp) {
167 			ext = &odev->d_exts[odev->d_nctrl];
168 			ext->ctrl = odev->d_nctrl;
169 			ext->control_no = -1;
170 			ext->type = MIXT_GROUP;
171 			ext->desc = MIXEXT_SCOPE_INPUT;
172 			ext->timestamp = gethrtime();
173 			(void) snprintf(ext->id, sizeof (ext->id), "RECORD");
174 			odev->d_rec_grp = odev->d_nctrl;
175 			odev->d_nctrl++;
176 		}
177 		scope = MIXEXT_SCOPE_INPUT;
178 		parent = odev->d_rec_grp;
179 	} else if (desc.acd_flags & AUDIO_CTRL_FLAG_MONITOR) {
180 		if (!odev->d_mon_grp) {
181 			ext = &odev->d_exts[odev->d_nctrl];
182 			ext->ctrl = odev->d_nctrl;
183 			ext->control_no = -1;
184 			ext->type = MIXT_GROUP;
185 			ext->desc = MIXEXT_SCOPE_MONITOR;
186 			ext->timestamp = gethrtime();
187 			(void) snprintf(ext->id, sizeof (ext->id), "MONITOR");
188 			odev->d_mon_grp = odev->d_nctrl;
189 			odev->d_nctrl++;
190 		}
191 		scope = MIXEXT_SCOPE_MONITOR;
192 		parent = odev->d_mon_grp;
193 	} else {
194 		if (!odev->d_misc_grp) {
195 			ext = &odev->d_exts[odev->d_nctrl];
196 			ext->ctrl = odev->d_nctrl;
197 			ext->control_no = -1;
198 			ext->type = MIXT_GROUP;
199 			ext->desc = MIXEXT_SCOPE_OTHER;
200 			ext->timestamp = gethrtime();
201 			(void) snprintf(ext->id, sizeof (ext->id), "MISC");
202 			odev->d_misc_grp = odev->d_nctrl;
203 			odev->d_nctrl++;
204 		}
205 		scope = MIXEXT_SCOPE_OTHER;
206 		parent = odev->d_misc_grp;
207 	}
208 
209 	name = desc.acd_name ? desc.acd_name : "";
210 
211 	if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) {
212 		ext = &odev->d_exts[odev->d_nctrl];
213 		ext->ctrl = odev->d_nctrl;
214 		ext->control_no = -1;
215 		ext->type = MIXT_GROUP;
216 		ext->timestamp = gethrtime();
217 		ext->parent = parent;
218 		ext->desc = scope;
219 		(void) snprintf(ext->id, sizeof (ext->id), "%s", name);
220 		(void) snprintf(ext->extname, sizeof (ext->extname),
221 		    "%s", name);
222 		parent = odev->d_nctrl++;
223 	}
224 
225 	/* Next available open entry */
226 	ext = &odev->d_exts[odev->d_nctrl];
227 
228 	/* Record the underlying control handle */
229 	odev->d_ctrls[odev->d_nctrl] = ctrl;
230 
231 	/*
232 	 * Now setup the oss entry
233 	 */
234 
235 	ext->ctrl = odev->d_nctrl;
236 	ext->control_no = -1;
237 	ext->maxvalue = (int)desc.acd_maxvalue;
238 	ext->minvalue = (int)desc.acd_minvalue;
239 	ext->timestamp = gethrtime();
240 	ext->parent = parent;
241 	ext->desc = scope;
242 	/* all controls should be pollable for now */
243 	flags = MIXF_POLL;
244 
245 	/*
246 	 * The following flags are intended to help out applications
247 	 * which need to figure out where to place certain controls.
248 	 * A few further words of guidance:
249 	 *
250 	 * Apps that just want a single master volume control should
251 	 * adjust the control(s) that are labelled with MIXF_PCMVOL if
252 	 * present.  They can fall back to adjusting all MAINVOL
253 	 * levels instead, if no PCMVOL is present.
254 	 *
255 	 * Controls that are one type on a certain device might be a
256 	 * different type on another device.  For example,
257 	 * audiopci/ak4531 can adjust input gains for individual
258 	 * levels, but lacks a master record gain.  AC'97, on the
259 	 * other hand, has individual monitor gains for inputs, but
260 	 * only a single master recording gain.
261 	 */
262 	if (desc.acd_flags & AUDIO_CTRL_FLAG_READABLE)
263 		flags |= MIXF_READABLE;
264 	if (desc.acd_flags & AUDIO_CTRL_FLAG_WRITEABLE)
265 		flags |= MIXF_WRITEABLE;
266 	if (desc.acd_flags & AUDIO_CTRL_FLAG_CENTIBEL)
267 		flags |= MIXF_CENTIBEL;
268 	if (desc.acd_flags & AUDIO_CTRL_FLAG_DECIBEL)
269 		flags |= MIXF_DECIBEL;
270 	if (desc.acd_flags & AUDIO_CTRL_FLAG_MAINVOL)
271 		flags |= MIXF_MAINVOL;
272 	if (desc.acd_flags & AUDIO_CTRL_FLAG_PCMVOL)
273 		flags |= MIXF_PCMVOL;
274 	if (desc.acd_flags & AUDIO_CTRL_FLAG_RECVOL)
275 		flags |= MIXF_RECVOL;
276 	if (desc.acd_flags & AUDIO_CTRL_FLAG_MONVOL)
277 		flags |= MIXF_MONVOL;
278 	ext->flags = flags;
279 
280 	(void) snprintf(ext->id, sizeof (ext->id), "%s", name);
281 
282 	/*
283 	 * For now just use the same extname as the real name.
284 	 */
285 	(void) snprintf(ext->extname, sizeof (ext->extname), name);
286 
287 	/*
288 	 * Now we deal with various control types.
289 	 */
290 	switch (desc.acd_type) {
291 	case AUDIO_CTRL_TYPE_BOOLEAN:
292 		ext->type = MIXT_ONOFF;
293 		ext->enumbit = -1;
294 		break;
295 	case AUDIO_CTRL_TYPE_STEREO:
296 		ext->type = MIXT_STEREOSLIDER;
297 		break;
298 	case AUDIO_CTRL_TYPE_MONO:
299 		ext->type = MIXT_MONOSLIDER;
300 		break;
301 	case AUDIO_CTRL_TYPE_ENUM:
302 
303 		if (desc.acd_flags & AUDIO_CTRL_FLAG_MULTI) {
304 			/*
305 			 * We turn AUDIO_CTRL_FLAG_MULTI into a group
306 			 * of checkboxes, since OSS can't represent it
307 			 * natively.
308 			 */
309 			mask = desc.acd_maxvalue;
310 			bit = 0;
311 			while (mask) {
312 				if (mask & 1) {
313 					ext = &odev->d_exts[odev->d_nctrl];
314 					(void) snprintf(ext->extname,
315 					    sizeof (ext->extname), "%s.%s",
316 					    name, desc.acd_enum[bit]);
317 					(void) snprintf(ext->id,
318 					    sizeof (ext->id), "%s",
319 					    desc.acd_enum[bit]);
320 					ext->ctrl = odev->d_nctrl;
321 					ext->control_no = -1;
322 					ext->parent = parent;
323 					ext->timestamp = gethrtime();
324 					ext->type = MIXT_ONOFF;
325 					ext->minvalue = 0;
326 					ext->maxvalue = 1;
327 					ext->enumbit = bit;
328 					ext->flags = flags;
329 					odev->d_ctrls[odev->d_nctrl] = ctrl;
330 					odev->d_nctrl++;
331 				}
332 				bit++;
333 				mask >>= 1;
334 			}
335 			return (AUDIO_WALK_CONTINUE);
336 		} else {
337 			/*
338 			 * NB: This is sufficient only for controls
339 			 * with a single value.  It cannot express the
340 			 * richer bitmask capabilities.
341 			 */
342 			ext->type = MIXT_ENUM;
343 			ext->minvalue = 0;
344 
345 			/*
346 			 * For an enumaration, we need to figure out
347 			 * which values are present, and set the
348 			 * appropriate mask and max value.
349 			 */
350 			bzero(ext->enum_present, sizeof (ext->enum_present));
351 			mask = desc.acd_maxvalue;
352 			bit = 0;
353 			while (mask) {
354 				if (mask & 1) {
355 					ext->enum_present[bit / 8] |=
356 					    (1 << (bit % 8));
357 				}
358 				mask >>= 1;
359 				bit++;
360 			}
361 			ext->maxvalue = bit;
362 		}
363 		break;
364 
365 	case AUDIO_CTRL_TYPE_METER:
366 	default:
367 		/* Its an unknown or unsupported (for now) control, skip */
368 		return (AUDIO_WALK_CONTINUE);
369 	}
370 
371 	odev->d_nctrl++;
372 
373 	return (AUDIO_WALK_CONTINUE);
374 }
375 
376 /*
377  * Free up an OSS user land control to internal control,
378  * helper table.
379  */
380 static void
381 oss_free_controls(ossdev_t *odev)
382 {
383 	kmem_free(odev->d_ctrls, sizeof (audio_ctrl_t *) * odev->d_nalloc);
384 	kmem_free(odev->d_exts, sizeof (oss_mixext) * odev->d_nalloc);
385 	odev->d_nctrl = 0;
386 	odev->d_nalloc = 0;
387 }
388 
389 /*
390  * Allocate and fill in an OSS user land controls to internal controls
391  * helper table. This is done on one audio_dev device.
392  */
393 static void
394 oss_alloc_controls(ossdev_t *odev)
395 {
396 	audio_dev_t		*d = odev->d_dev;
397 	int			nctrl = 0;
398 	oss_mixext		*ext;
399 	oss_mixext_root		*root_data;
400 
401 	/* Find out who many entries we need */
402 	auclnt_walk_controls(d, oss_cnt_controls, &nctrl);
403 	nctrl++;		/* Needs space for the device root node */
404 	nctrl++;		/* Needs space for the device ext marker */
405 	nctrl++;		/* Needs space for the play group */
406 	nctrl++;		/* Needs space for the record group */
407 	nctrl++;		/* Needs space for the monitor group */
408 	nctrl++;		/* Needs space for the tone group */
409 	nctrl++;		/* Needs space for the 3D group */
410 	nctrl++;		/* Needs space for the misc group */
411 
412 	/* Allocate the OSS to boomer helper table */
413 	odev->d_nalloc = nctrl;
414 	odev->d_ctrls = kmem_zalloc(sizeof (audio_ctrl_t *) * nctrl, KM_SLEEP);
415 	odev->d_exts = kmem_zalloc(sizeof (oss_mixext) * nctrl, KM_SLEEP);
416 
417 	/*
418 	 * Setup special case outputs to output OSS routes helper tables
419 	 */
420 
421 	/*
422 	 * Root node is first, that way all others parent is this one
423 	 */
424 	ext = &odev->d_exts[odev->d_nctrl];
425 	ext->ctrl = 0;
426 	ext->parent = -1;
427 	ext->type = MIXT_DEVROOT;
428 	ext->timestamp = gethrtime();
429 	(void) snprintf(ext->id, sizeof (ext->id), "DEVROOT");
430 	/*
431 	 * Root data... nobody should be using this though.
432 	 */
433 	root_data = (oss_mixext_root *)&ext->data;
434 	(void) snprintf(root_data->name, sizeof (root_data->name), "%s",
435 	    auclnt_get_dev_name(d));
436 	(void) snprintf(root_data->id, sizeof (root_data->id), "%s",
437 	    auclnt_get_dev_name(d));
438 
439 	odev->d_nctrl++;
440 
441 	/*
442 	 * Insert an extra marker -- needed to keep layout apps hapy.
443 	 * This prevents some apps from assuming we are in "LEGACY" mode.
444 	 */
445 	ext = &odev->d_exts[odev->d_nctrl];
446 	ext->ctrl = odev->d_nctrl;
447 	ext->control_no = -1;
448 	ext->type = MIXT_MARKER;
449 	ext->timestamp = gethrtime();
450 	ext->parent = 0;
451 	odev->d_nctrl++;
452 
453 	/* Fill in the complete table now */
454 	auclnt_walk_controls(d, oss_add_control, odev);
455 
456 	/* Update the update_counter reference counter for groups */
457 	for (nctrl = 0; nctrl < odev->d_nctrl; nctrl++) {
458 		int i;
459 
460 		ext = &odev->d_exts[nctrl];
461 		i = ext->parent;
462 		while ((i >= 0) && (i < odev->d_nctrl)) {
463 
464 			ext = &odev->d_exts[i];
465 			ASSERT(ext->parent < i);
466 			ASSERT((ext->type == MIXT_GROUP) ||
467 			    (ext->type == MIXT_DEVROOT));
468 			ext->update_counter++;
469 			i = ext->parent;
470 		}
471 	}
472 
473 	ASSERT(odev->d_nctrl <= odev->d_nalloc);
474 }
475 
476 static int
477 oss_open(audio_client_t *c, int oflag)
478 {
479 	int		rv;
480 	ossdev_t	*odev;
481 	ossclient_t	*sc;
482 	audio_stream_t	*isp, *osp;
483 
484 	isp = auclnt_input_stream(c);
485 	osp = auclnt_output_stream(c);
486 
487 	/* note that OSS always uses nonblocking open() semantics */
488 	if ((rv = auclnt_open(c, AUDIO_FORMAT_PCM, oflag | FNDELAY)) != 0) {
489 		return (rv);
490 	}
491 
492 	if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) {
493 		auclnt_close(c);
494 		return (ENOMEM);
495 	}
496 	auclnt_set_private(c, sc);
497 
498 	odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP);
499 
500 	/* set a couple of common fields */
501 	sc->o_client = c;
502 	sc->o_ossdev = odev;
503 
504 	/* set all default parameters */
505 	if (oflag & FWRITE) {
506 		if (((rv = auclnt_set_format(osp, OSS_FMT)) != 0) ||
507 		    ((rv = auclnt_set_rate(osp, OSS_RATE)) != 0) ||
508 		    ((rv = auclnt_set_channels(osp, OSS_CHANNELS)) != 0)) {
509 			goto failed;
510 		}
511 	}
512 
513 	if (oflag & FREAD) {
514 		if (((rv = auclnt_set_format(isp, OSS_FMT)) != 0) ||
515 		    ((rv = auclnt_set_rate(isp, OSS_RATE)) != 0) ||
516 		    ((rv = auclnt_set_channels(isp, OSS_CHANNELS)) != 0)) {
517 			goto failed;
518 		}
519 	}
520 
521 	return (0);
522 
523 failed:
524 	auclnt_close(c);
525 	return (rv);
526 }
527 
528 static void
529 oss_close(audio_client_t *c)
530 {
531 	ossclient_t	*sc;
532 
533 	sc = auclnt_get_private(c);
534 
535 	if (ddi_can_receive_sig() || (ddi_get_pid() == 0)) {
536 		(void) auclnt_drain(c);
537 	}
538 
539 	kmem_free(sc, sizeof (*sc));
540 
541 	auclnt_close(c);
542 }
543 
544 /*
545  * This is used to generate an array of names for an enumeration
546  */
547 static ushort_t
548 oss_set_enum(oss_mixer_enuminfo *ei, ushort_t nxt, const char *name)
549 {
550 	uint32_t	n;
551 
552 	/* Get current entry to fill in */
553 	n = ei->nvalues;
554 	(void) snprintf(&ei->strings[nxt], ((sizeof (ei->strings) - nxt) - 1),
555 	    "%s", name);
556 	ei->strindex[n] = nxt;
557 
558 	/* Adjust everything for next entry */
559 	nxt += strnlen(name, ((sizeof (ei->strings) - nxt) - 1));
560 	ei->strings[nxt++] = '\0';
561 
562 	ei->nvalues++;
563 	return (nxt);
564 }
565 
566 /*
567  * The following two functions are used to count the number of devices
568  * in under the boomer framework.
569  *
570  * We actually report the highest "index", and then if an audio device
571  * is not found, we report a bogus removed device for it in the actual
572  * ioctls.  This goofiness is required to make the OSS API happy.
573  */
574 int
575 oss_dev_walker(audio_dev_t *d, void *arg)
576 {
577 	int		*pcnt = arg;
578 	int		cnt;
579 	int		index;
580 
581 	cnt = *pcnt;
582 	index = auclnt_get_dev_index(d);
583 	if ((index + 1) > cnt) {
584 		cnt = index + 1;
585 		*pcnt = cnt;
586 	}
587 
588 	return (AUDIO_WALK_CONTINUE);
589 }
590 
591 static int
592 oss_cnt_devs(void)
593 {
594 	int cnt = 0;
595 
596 	auclnt_walk_devs(oss_dev_walker, &cnt);
597 	return (cnt);
598 }
599 
600 static int
601 sndctl_dsp_speed(audio_client_t *c, int *ratep)
602 {
603 	int		rv;
604 	int		rate;
605 	int		oflag;
606 
607 	rate = *ratep;
608 
609 	oflag = auclnt_get_oflag(c);
610 	if (oflag & FREAD) {
611 		if ((rv = auclnt_set_rate(auclnt_input_stream(c), rate)) != 0)
612 			return (rv);
613 	}
614 
615 	if (oflag & FWRITE) {
616 		if ((rv = auclnt_set_rate(auclnt_output_stream(c), rate)) != 0)
617 			return (rv);
618 	}
619 
620 	return (0);
621 }
622 
623 static int
624 sndctl_dsp_setfmt(audio_client_t *c, int *fmtp)
625 {
626 	int		rv;
627 	int		fmt;
628 	int		i;
629 	int		oflag;
630 
631 	oflag = auclnt_get_oflag(c);
632 
633 	if (*fmtp != AFMT_QUERY) {
634 		/* convert from OSS */
635 		for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) {
636 			if (oss_formats[i].oss == *fmtp) {
637 				fmt = oss_formats[i].fmt;
638 				break;
639 			}
640 		}
641 		if (fmt == AUDIO_FORMAT_NONE) {
642 			/* if format not known, return ENOTSUP */
643 			return (ENOTSUP);
644 		}
645 
646 		if (oflag & FWRITE) {
647 			rv = auclnt_set_format(auclnt_output_stream(c), fmt);
648 			if (rv != 0)
649 				return (rv);
650 		}
651 
652 		if (oflag & FREAD) {
653 			rv = auclnt_set_format(auclnt_input_stream(c), fmt);
654 			if (rv != 0)
655 				return (rv);
656 		}
657 	}
658 
659 	if (oflag & FWRITE) {
660 		fmt = auclnt_get_format(auclnt_output_stream(c));
661 	} else if (oflag & FREAD) {
662 		fmt = auclnt_get_format(auclnt_input_stream(c));
663 	}
664 
665 	/* convert back to OSS */
666 	*(int *)fmtp = AFMT_QUERY;
667 	for (i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) {
668 		if (oss_formats[i].fmt == fmt) {
669 			*(int *)fmtp = oss_formats[i].oss;
670 		}
671 	}
672 
673 	return (0);
674 }
675 
676 static int
677 sndctl_dsp_getfmts(audio_client_t *c, int *fmtsp)
678 {
679 	_NOTE(ARGUNUSED(c));
680 
681 	/*
682 	 * For now, we support all the standard ones.  Later we might
683 	 * add in conditional support for AC3.
684 	 */
685 	*fmtsp = (AFMT_MU_LAW | AFMT_A_LAW |
686 	    AFMT_U8 | AFMT_S8 |
687 	    AFMT_S16_LE |AFMT_S16_BE |
688 	    AFMT_S24_LE | AFMT_S24_BE |
689 	    AFMT_S32_LE | AFMT_S32_BE |
690 	    AFMT_S24_PACKED);
691 
692 	return (0);
693 }
694 
695 static int
696 sndctl_dsp_channels(audio_client_t *c, int *chanp)
697 {
698 	int		rv;
699 	int		nchan;
700 	int		oflag;
701 
702 	oflag = auclnt_get_oflag(c);
703 
704 	nchan = *chanp;
705 	if (nchan != 0) {
706 		if (oflag & FWRITE) {
707 			rv = auclnt_set_channels(auclnt_output_stream(c),
708 			    nchan);
709 			if (rv != 0)
710 				return (rv);
711 		}
712 
713 		if (oflag & FREAD) {
714 			rv = auclnt_set_channels(auclnt_input_stream(c), nchan);
715 			if (rv != 0)
716 				return (rv);
717 		}
718 	}
719 
720 	if (oflag & FWRITE) {
721 		nchan = auclnt_get_channels(auclnt_output_stream(c));
722 	} else if (oflag & FREAD) {
723 		nchan = auclnt_get_channels(auclnt_input_stream(c));
724 	}
725 	*chanp = nchan;
726 	return (0);
727 }
728 
729 static int
730 sndctl_dsp_stereo(audio_client_t *c, int *onoff)
731 {
732 	int	nchan;
733 
734 	switch (*onoff) {
735 	case 0:
736 		nchan = 1;
737 		break;
738 	case 1:
739 		nchan = 2;
740 		break;
741 	default:
742 		return (EINVAL);
743 	}
744 
745 	return (sndctl_dsp_channels(c, &nchan));
746 }
747 
748 static int
749 sndctl_dsp_post(audio_client_t *c)
750 {
751 	if (auclnt_get_oflag(c) & FWRITE) {
752 		audio_stream_t	*sp = auclnt_output_stream(c);
753 		auclnt_flush(sp);
754 		auclnt_clear_paused(sp);
755 	}
756 	return (0);
757 }
758 
759 static int
760 sndctl_dsp_getcaps(audio_client_t *c, int *capsp)
761 {
762 	int		ncaps;
763 	int		osscaps = 0;
764 
765 	ncaps = auclnt_get_dev_capab(auclnt_get_dev(c));
766 
767 	if (ncaps & AUDIO_CLIENT_CAP_PLAY)
768 		osscaps |= PCM_CAP_OUTPUT;
769 	if (ncaps & AUDIO_CLIENT_CAP_RECORD)
770 		osscaps |= PCM_CAP_INPUT;
771 	if (ncaps & AUDIO_CLIENT_CAP_DUPLEX)
772 		osscaps |= PCM_CAP_DUPLEX;
773 
774 	*capsp = osscaps;
775 	return (0);
776 }
777 
778 static int
779 sndctl_dsp_gettrigger(audio_client_t *c, int *trigp)
780 {
781 	int		triggers = 0;
782 	int		oflag;
783 
784 	oflag = auclnt_get_oflag(c);
785 
786 	if (oflag & FWRITE) {
787 		if (!auclnt_is_paused(auclnt_output_stream(c))) {
788 			triggers |= PCM_ENABLE_OUTPUT;
789 		}
790 	}
791 
792 	if (oflag & FREAD) {
793 		if (!auclnt_is_paused(auclnt_input_stream(c))) {
794 			triggers |= PCM_ENABLE_INPUT;
795 		}
796 	}
797 	*trigp = triggers;
798 
799 	return (0);
800 }
801 
802 static int
803 sndctl_dsp_settrigger(audio_client_t *c, int *trigp)
804 {
805 	int		triggers;
806 	int		oflag;
807 
808 	oflag = auclnt_get_oflag(c);
809 	triggers = *trigp;
810 
811 	if ((oflag & FWRITE) && (triggers & PCM_ENABLE_OUTPUT)) {
812 		auclnt_clear_paused(auclnt_output_stream(c));
813 	}
814 
815 	if ((oflag & FREAD) && (triggers & PCM_ENABLE_INPUT)) {
816 		auclnt_clear_paused(auclnt_input_stream(c));
817 	}
818 
819 	return (0);
820 }
821 
822 struct oss_legacy_volume {
823 	pid_t		pid;
824 	uint8_t		ogain;
825 	uint8_t		igain;
826 };
827 
828 static int
829 oss_legacy_volume_walker(audio_client_t *c, void *arg)
830 {
831 	struct oss_legacy_volume	 *olv = arg;
832 
833 	if (auclnt_get_pid(c) == olv->pid) {
834 		if (olv->ogain <= 100) {
835 			auclnt_set_gain(auclnt_output_stream(c), olv->ogain);
836 		}
837 		if (olv->igain <= 100) {
838 			auclnt_set_gain(auclnt_input_stream(c), olv->igain);
839 		}
840 	}
841 	return (AUDIO_WALK_CONTINUE);
842 }
843 
844 static void
845 oss_set_legacy_volume(audio_client_t *c, uint8_t ogain, uint8_t igain)
846 {
847 	struct oss_legacy_volume olv;
848 
849 	olv.pid = auclnt_get_pid(c);
850 	olv.ogain = ogain;
851 	olv.igain = igain;
852 	auclnt_dev_walk_clients(auclnt_get_dev(c),
853 	    oss_legacy_volume_walker, &olv);
854 }
855 
856 static int
857 sndctl_dsp_getplayvol(audio_client_t *c, int *volp)
858 {
859 	int	vol;
860 
861 	/* convert monophonic soft value to OSS stereo value */
862 	vol = auclnt_get_gain(auclnt_output_stream(c));
863 	*volp = vol | (vol << 8);
864 	return (0);
865 }
866 
867 static int
868 sndctl_dsp_setplayvol(audio_client_t *c, int *volp)
869 {
870 	uint8_t		vol;
871 
872 	vol = *volp & 0xff;
873 	if (vol > 100) {
874 		return (EINVAL);
875 	}
876 
877 	auclnt_set_gain(auclnt_output_stream(c), vol);
878 	*volp = (vol | (vol << 8));
879 
880 	return (0);
881 }
882 
883 static int
884 sndctl_dsp_getrecvol(audio_client_t *c, int *volp)
885 {
886 	int	vol;
887 
888 	vol = auclnt_get_gain(auclnt_input_stream(c));
889 	*volp = (vol | (vol << 8));
890 	return (0);
891 }
892 
893 static int
894 sndctl_dsp_setrecvol(audio_client_t *c, int *volp)
895 {
896 	uint8_t		vol;
897 
898 	vol = *volp & 0xff;
899 	if (vol > 100) {
900 		return (EINVAL);
901 	}
902 
903 	auclnt_set_gain(auclnt_input_stream(c), vol);
904 	*volp = (vol | (vol << 8));
905 
906 	return (0);
907 }
908 
909 static int
910 sound_mixer_write_ogain(audio_client_t *c, int *volp)
911 {
912 	uint8_t		vol;
913 
914 	vol = *volp & 0xff;
915 	if (vol > 100) {
916 		return (EINVAL);
917 	}
918 	oss_set_legacy_volume(c, vol, 255);
919 	*volp = (vol | (vol << 8));
920 	return (0);
921 }
922 
923 static int
924 sound_mixer_write_igain(audio_client_t *c, int *volp)
925 {
926 	uint8_t		vol;
927 
928 	vol = *volp & 0xff;
929 	if (vol > 100) {
930 		return (EINVAL);
931 	}
932 	oss_set_legacy_volume(c, 255, vol);
933 	*volp = (vol | (vol << 8));
934 	return (0);
935 }
936 
937 static int
938 sndctl_dsp_readctl(audio_client_t *c, oss_digital_control *ctl)
939 {
940 	/* SPDIF: need to add support with spdif */
941 	_NOTE(ARGUNUSED(c));
942 	_NOTE(ARGUNUSED(ctl));
943 	return (ENOTSUP);
944 }
945 
946 static int
947 sndctl_dsp_writectl(audio_client_t *c, oss_digital_control *ctl)
948 {
949 	/* SPDIF: need to add support with spdif */
950 	_NOTE(ARGUNUSED(c));
951 	_NOTE(ARGUNUSED(ctl));
952 	return (ENOTSUP);
953 }
954 
955 static int
956 sndctl_dsp_cookedmode(audio_client_t *c, int *rvp)
957 {
958 	_NOTE(ARGUNUSED(c));
959 
960 	/* We are *always* in cooked mode -- at least until we have AC3. */
961 	if (*rvp == 0) {
962 		return (ENOTSUP);
963 	} else {
964 		return (0);
965 	}
966 }
967 
968 static int
969 sndctl_dsp_silence(audio_client_t *c)
970 {
971 	if (auclnt_get_oflag(c) & FWRITE) {
972 		audio_stream_t	*sp = auclnt_output_stream(c);
973 		auclnt_set_paused(sp);
974 		auclnt_flush(sp);
975 	}
976 	return (0);
977 }
978 
979 static int
980 sndctl_dsp_skip(audio_client_t *c)
981 {
982 	if (auclnt_get_oflag(c) & FWRITE) {
983 		audio_stream_t	*sp = auclnt_output_stream(c);
984 		auclnt_set_paused(sp);
985 		auclnt_flush(sp);
986 		auclnt_clear_paused(sp);
987 	}
988 	return (0);
989 }
990 
991 static int
992 sndctl_dsp_halt_input(audio_client_t *c)
993 {
994 	if (auclnt_get_oflag(c) & FREAD) {
995 		audio_stream_t	*sp = auclnt_input_stream(c);
996 		auclnt_set_paused(sp);
997 		auclnt_flush(sp);
998 	}
999 	return (0);
1000 }
1001 
1002 static int
1003 sndctl_dsp_halt_output(audio_client_t *c)
1004 {
1005 	if (auclnt_get_oflag(c) & FWRITE) {
1006 		audio_stream_t	*sp = auclnt_output_stream(c);
1007 		auclnt_set_paused(sp);
1008 		auclnt_flush(sp);
1009 	}
1010 	return (0);
1011 }
1012 
1013 static int
1014 sndctl_dsp_halt(audio_client_t *c)
1015 {
1016 	(void) sndctl_dsp_halt_input(c);
1017 	(void) sndctl_dsp_halt_output(c);
1018 	return (0);
1019 }
1020 
1021 static int
1022 sndctl_dsp_sync(audio_client_t *c)
1023 {
1024 	return (auclnt_drain(c));
1025 }
1026 
1027 static int
1028 sndctl_dsp_setfragment(audio_client_t *c, int *fragp)
1029 {
1030 	_NOTE(ARGUNUSED(c));
1031 	_NOTE(ARGUNUSED(fragp));
1032 	/*
1033 	 * We don't really implement this "properly" at this time.
1034 	 * The problems with this ioctl are various: the API insists
1035 	 * that fragment sizes be a power of two -- and we can't cope
1036 	 * with accurately reporting fragment sizes in the face of
1037 	 * mixing and format conversion.
1038 	 *
1039 	 * Well behaved applications should really not use this API.
1040 	 *
1041 	 * According to the OSS API documentation, the values provided
1042 	 * are nothing more than a "hint" and not to be relied upon
1043 	 * anyway.  And we aren't obligated to report the actual
1044 	 * values back!
1045 	 */
1046 	return (0);
1047 }
1048 
1049 /*
1050  * A word about recsrc, and playtgt ioctls: We don't allow ordinary DSP
1051  * applications to change port configurations, because these could have a
1052  * bad effect for other applications.  Instead, these settings have to
1053  * be changed using the master mixer panel.  In order to make applications
1054  * happy, we just present a single "default" source/target.
1055  */
1056 static int
1057 sndctl_dsp_get_recsrc_names(audio_client_t *c, oss_mixer_enuminfo *ei)
1058 {
1059 	_NOTE(ARGUNUSED(c));
1060 
1061 	ei->nvalues = 1;
1062 	(void) snprintf(ei->strings, sizeof (ei->strings), "default");
1063 	ei->strindex[0] = 0;
1064 
1065 	return (0);
1066 }
1067 
1068 static int
1069 sndctl_dsp_get_recsrc(audio_client_t *c, int *srcp)
1070 {
1071 	_NOTE(ARGUNUSED(c));
1072 	*srcp = 0;
1073 	return (0);
1074 }
1075 
1076 static int
1077 sndctl_dsp_set_recsrc(audio_client_t *c, int *srcp)
1078 {
1079 	_NOTE(ARGUNUSED(c));
1080 	*srcp = 0;
1081 	return (0);
1082 }
1083 
1084 static int
1085 sndctl_dsp_get_playtgt_names(audio_client_t *c, oss_mixer_enuminfo *ei)
1086 {
1087 	_NOTE(ARGUNUSED(c));
1088 
1089 	ei->nvalues = 1;
1090 	(void) snprintf(ei->strings, sizeof (ei->strings), "default");
1091 	ei->strindex[0] = 0;
1092 
1093 	return (0);
1094 }
1095 
1096 static int
1097 sndctl_dsp_get_playtgt(audio_client_t *c, int *tgtp)
1098 {
1099 	_NOTE(ARGUNUSED(c));
1100 	*tgtp = 0;
1101 	return (0);
1102 }
1103 
1104 static int
1105 sndctl_dsp_set_playtgt(audio_client_t *c, int *tgtp)
1106 {
1107 	_NOTE(ARGUNUSED(c));
1108 	*tgtp = 0;
1109 	return (0);
1110 }
1111 
1112 static int
1113 sndctl_sysinfo(oss_sysinfo *si)
1114 {
1115 	bzero(si, sizeof (*si));
1116 	(void) snprintf(si->product, sizeof (si->product), "SunOS Audio");
1117 	(void) snprintf(si->version, sizeof (si->version), "4.0");
1118 	si->versionnum = OSS_VERSION;
1119 	si->numcards = oss_cnt_devs();
1120 	si->nummixers = si->numcards - 1;
1121 	si->numaudios = si->numcards - 1;
1122 	si->numaudioengines = si->numaudios;
1123 	(void) snprintf(si->license, sizeof (si->license), "CDDL");
1124 	return (0);
1125 }
1126 
1127 static int
1128 sndctl_cardinfo(audio_client_t *c, oss_card_info *ci)
1129 {
1130 	audio_dev_t	*d;
1131 	void		*iter;
1132 	const char 	*info;
1133 	int		n;
1134 	boolean_t	release;
1135 
1136 	if ((n = ci->card) == -1) {
1137 		release = B_FALSE;
1138 		d = auclnt_get_dev(c);
1139 		n = auclnt_get_dev_index(d);
1140 	} else {
1141 		release = B_TRUE;
1142 		d = auclnt_hold_dev_by_index(n);
1143 	}
1144 
1145 	bzero(ci, sizeof (*ci));
1146 	ci->card = n;
1147 
1148 	if (d == NULL) {
1149 		/*
1150 		 * If device removed (e.g. for DR), then
1151 		 * report a bogus removed entry.
1152 		 */
1153 		(void) snprintf(ci->shortname, sizeof (ci->shortname),
1154 		    "<removed>");
1155 		(void) snprintf(ci->longname, sizeof (ci->longname),
1156 		    "<removed>");
1157 		return (0);
1158 	}
1159 
1160 	(void) snprintf(ci->shortname, sizeof (ci->shortname),
1161 	    "%s", auclnt_get_dev_name(d));
1162 	(void) snprintf(ci->longname, sizeof (ci->longname),
1163 	    "%s (%s)", auclnt_get_dev_description(d),
1164 	    auclnt_get_dev_version(d));
1165 
1166 	iter = NULL;
1167 	while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) {
1168 		(void) strlcat(ci->hw_info, info, sizeof (ci->hw_info));
1169 		(void) strlcat(ci->hw_info, "\n", sizeof (ci->hw_info));
1170 	}
1171 
1172 	/*
1173 	 * We don't report interrupt counts, ack counts (which are
1174 	 * just "read" interrupts, not spurious), or any other flags.
1175 	 * Nothing should be using any of this data anyway ... these
1176 	 * values were intended for 4Front's debugging purposes.  In
1177 	 * Solaris, drivers should use interrupt kstats to report
1178 	 * interrupt related statistics.
1179 	 */
1180 	if (release)
1181 		auclnt_release_dev(d);
1182 	return (0);
1183 }
1184 
1185 static int
1186 audioinfo_walker(audio_engine_t *e, void *a)
1187 {
1188 	oss_audioinfo *si = a;
1189 	int fmt, nchan, rate, cap;
1190 
1191 	fmt = auclnt_engine_get_format(e);
1192 	nchan = auclnt_engine_get_channels(e);
1193 	rate = auclnt_engine_get_rate(e);
1194 	cap = auclnt_engine_get_capab(e);
1195 
1196 	for (int i = 0; oss_formats[i].fmt != AUDIO_FORMAT_NONE; i++) {
1197 		if (fmt == oss_formats[i].fmt) {
1198 			if (cap & AUDIO_CLIENT_CAP_PLAY) {
1199 				si->oformats |= oss_formats[i].oss;
1200 			}
1201 			if (cap & AUDIO_CLIENT_CAP_RECORD) {
1202 				si->iformats |= oss_formats[i].oss;
1203 			}
1204 			break;
1205 		}
1206 	}
1207 	si->max_channels = max(nchan, si->max_channels);
1208 	si->max_rate = max(rate, si->max_rate);
1209 
1210 	return (AUDIO_WALK_CONTINUE);
1211 }
1212 
1213 static int
1214 sndctl_audioinfo(audio_client_t *c, oss_audioinfo *si)
1215 {
1216 	audio_dev_t		*d;
1217 	const char		*name;
1218 	int			n;
1219 	boolean_t		release;
1220 	unsigned		cap;
1221 
1222 	if ((n = si->dev) == -1) {
1223 		release = B_FALSE;
1224 		d = auclnt_get_dev(c);
1225 		n = auclnt_get_dev_index(d);
1226 	} else {
1227 		release = B_TRUE;
1228 		n++;	/* skip pseudo device */
1229 		d = auclnt_hold_dev_by_index(n);
1230 	}
1231 
1232 	bzero(si, sizeof (*si));
1233 	si->dev = n - 1;
1234 
1235 	if (d == NULL) {
1236 		/* if device not present, forge a false entry */
1237 		si->card_number = n;
1238 		si->mixer_dev = n - 1;
1239 		si->legacy_device = -1;
1240 		si->enabled = 0;
1241 		(void) snprintf(si->name, sizeof (si->name), "<removed>");
1242 		return (0);
1243 	}
1244 
1245 	name = auclnt_get_dev_name(d);
1246 	(void) snprintf(si->name, sizeof (si->name), "%s", name);
1247 
1248 	si->legacy_device = auclnt_get_dev_number(d);
1249 	si->caps = 0;
1250 
1251 	auclnt_dev_walk_engines(d, audioinfo_walker, si);
1252 
1253 	cap = auclnt_get_dev_capab(d);
1254 
1255 	if (cap	& AUDIO_CLIENT_CAP_DUPLEX) {
1256 		si->caps |= PCM_CAP_DUPLEX;
1257 	}
1258 	if (cap & AUDIO_CLIENT_CAP_PLAY) {
1259 		si->caps |= PCM_CAP_OUTPUT;
1260 	}
1261 	if (cap & AUDIO_CLIENT_CAP_RECORD) {
1262 		si->caps |= PCM_CAP_INPUT;
1263 	}
1264 
1265 	if (si->caps != 0) {
1266 		/* AC3: PCM_CAP_MULTI would be wrong for an AC3 only device */
1267 		si->caps |= PCM_CAP_BATCH | PCM_CAP_TRIGGER | PCM_CAP_MULTI;
1268 		/* MMAP: we add PCM_CAP_MMAP when we we support it */
1269 		si->enabled = 1;
1270 		si->rate_source = si->dev;
1271 
1272 		/* we can convert PCM formats */
1273 		if ((si->iformats | si->oformats) &
1274 		    AUDIO_FORMAT_PCM) {
1275 			si->min_channels = min(2, si->max_channels);
1276 			si->min_rate = min(5000, si->max_rate);
1277 			si->caps |= PCM_CAP_FREERATE;
1278 		}
1279 		(void) snprintf(si->devnode, sizeof (si->devnode),
1280 		    "/dev/sound/%s:%ddsp",
1281 		    auclnt_get_dev_driver(d), auclnt_get_dev_instance(d));
1282 	} else {
1283 		si->enabled = 0;	/* stops apps from using us directly */
1284 		si->caps = PCM_CAP_VIRTUAL;
1285 		(void) snprintf(si->devnode, sizeof (si->devnode),
1286 		    "/dev/sndstat");
1287 	}
1288 
1289 	si->pid = -1;
1290 	(void) snprintf(si->handle, sizeof (si->handle), "%s", name);
1291 	(void) snprintf(si->label, sizeof (si->label), "%s", name);
1292 	si->latency = -1;
1293 	si->card_number = n;
1294 	si->mixer_dev = n - 1;
1295 
1296 	if (release)
1297 		auclnt_release_dev(d);
1298 
1299 	return (0);
1300 }
1301 
1302 static int
1303 sound_mixer_info(audio_client_t *c, mixer_info *mi)
1304 {
1305 	audio_dev_t	*d;
1306 	ossdev_t	*odev;
1307 	ossclient_t	*sc;
1308 	const char	*name;
1309 
1310 	sc = auclnt_get_private(c);
1311 	odev = sc->o_ossdev;
1312 
1313 	d = auclnt_get_dev(c);
1314 
1315 	name = auclnt_get_dev_name(d);
1316 	(void) snprintf(mi->id, sizeof (mi->id), "%s", name);
1317 	(void) snprintf(mi->name, sizeof (mi->name), "%s", name);
1318 	(void) snprintf(mi->handle, sizeof (mi->handle), "%s", name);
1319 	mi->modify_counter = odev->d_modify_cnt;
1320 	mi->card_number = auclnt_get_dev_index(d);
1321 	mi->port_number = 0;
1322 	return (0);
1323 }
1324 
1325 static int
1326 sound_mixer_read_devmask(audio_client_t *c, int *devmask)
1327 {
1328 	_NOTE(ARGUNUSED(c));
1329 	*devmask = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_IGAIN;
1330 	return (0);
1331 }
1332 
1333 static int
1334 sound_mixer_read_recmask(audio_client_t *c, int *recmask)
1335 {
1336 	_NOTE(ARGUNUSED(c));
1337 	*recmask = 0;
1338 	return (0);
1339 }
1340 
1341 static int
1342 sound_mixer_read_recsrc(audio_client_t *c, int *recsrc)
1343 {
1344 	_NOTE(ARGUNUSED(c));
1345 	*recsrc = 0;
1346 	return (0);
1347 }
1348 
1349 static int
1350 sound_mixer_read_caps(audio_client_t *c, int *caps)
1351 {
1352 	_NOTE(ARGUNUSED(c));
1353 	/* single recording source... sort of */
1354 	*caps = SOUND_CAP_EXCL_INPUT;
1355 	return (0);
1356 }
1357 
1358 static int
1359 sndctl_mixerinfo(audio_client_t *c, oss_mixerinfo *mi)
1360 {
1361 	audio_dev_t		*d;
1362 	ossdev_t 		*odev;
1363 	const char		*name;
1364 	int			n;
1365 	boolean_t		release = B_FALSE;
1366 
1367 	if ((n = mi->dev) == -1) {
1368 		release = B_FALSE;
1369 		d = auclnt_get_dev(c);
1370 		n = auclnt_get_dev_index(d);
1371 	} else {
1372 		release = B_TRUE;
1373 		n++;
1374 		d = auclnt_hold_dev_by_index(n);
1375 	}
1376 
1377 	bzero(mi, sizeof (*mi));
1378 	mi->dev = n - 1;
1379 
1380 	if (d == NULL) {
1381 		mi->card_number = n;
1382 		mi->enabled = 0;
1383 		mi->legacy_device = -1;
1384 		(void) snprintf(mi->name, sizeof (mi->name), "<removed>");
1385 		(void) snprintf(mi->id, sizeof (mi->id), "<removed>");
1386 		return (0);
1387 	}
1388 
1389 	if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) {
1390 		if (release)
1391 			auclnt_release_dev(d);
1392 		return (EINVAL);
1393 	}
1394 
1395 	name = auclnt_get_dev_name(d);
1396 	(void) snprintf(mi->name, sizeof (mi->name), "%s", name);
1397 	(void) snprintf(mi->id, sizeof (mi->id), "%s", name);
1398 	(void) snprintf(mi->handle, sizeof (mi->handle), "%s", name);
1399 	mi->modify_counter = odev->d_modify_cnt;
1400 	mi->card_number = auclnt_get_dev_index(d);
1401 	mi->legacy_device = auclnt_get_dev_number(d);
1402 	if (mi->legacy_device >= 0) {
1403 		(void) snprintf(mi->devnode, sizeof (mi->devnode),
1404 		    "/dev/sound/%s:%dmixer",
1405 		    auclnt_get_dev_driver(d), auclnt_get_dev_instance(d));
1406 		mi->enabled = 1;
1407 	} else {
1408 		/* special nodes use generic sndstat node */
1409 		(void) snprintf(mi->devnode, sizeof (mi->devnode),
1410 		    "/dev/sndstat");
1411 		mi->enabled = 0;
1412 	}
1413 	mi->nrext = odev->d_nctrl;
1414 
1415 	if (release)
1416 		auclnt_release_dev(d);
1417 
1418 	return (0);
1419 }
1420 
1421 static int
1422 sndctl_dsp_getblksize(audio_client_t *c, int *fragsz)
1423 {
1424 	int	oflag = auclnt_get_oflag(c);
1425 
1426 	if (oflag & FWRITE)
1427 		*fragsz  = auclnt_get_fragsz(auclnt_output_stream(c));
1428 	else if (oflag & FREAD)
1429 		*fragsz  = auclnt_get_fragsz(auclnt_input_stream(c));
1430 
1431 	return (0);
1432 }
1433 
1434 static int
1435 sndctl_dsp_getospace(audio_client_t *c, audio_buf_info *bi)
1436 {
1437 	audio_stream_t	*sp;
1438 	unsigned	n;
1439 
1440 	if ((auclnt_get_oflag(c) & FWRITE) == 0) {
1441 		return (EACCES);
1442 	}
1443 
1444 	sp = auclnt_output_stream(c);
1445 	n = auclnt_get_nframes(sp) - auclnt_get_count(sp);
1446 
1447 	bi->fragsize  = auclnt_get_fragsz(sp);
1448 	bi->fragstotal = auclnt_get_nfrags(sp);
1449 	bi->bytes = (n * auclnt_get_framesz(sp));
1450 	bi->fragments = bi->bytes / bi->fragsize;
1451 
1452 	return (0);
1453 }
1454 
1455 static int
1456 sndctl_dsp_getispace(audio_client_t *c, audio_buf_info *bi)
1457 {
1458 	audio_stream_t	*sp;
1459 	unsigned	n;
1460 
1461 	if ((auclnt_get_oflag(c) & FREAD) == 0) {
1462 		return (EACCES);
1463 	}
1464 
1465 	sp = auclnt_input_stream(c);
1466 	n = auclnt_get_count(sp);
1467 
1468 	bi->fragsize  = auclnt_get_fragsz(sp);
1469 	bi->fragstotal = auclnt_get_nfrags(sp);
1470 	bi->bytes = (n * auclnt_get_framesz(sp));
1471 	bi->fragments = bi->bytes / bi->fragsize;
1472 
1473 	return (0);
1474 }
1475 
1476 static int
1477 sndctl_dsp_getodelay(audio_client_t *c, int *bytes)
1478 {
1479 	unsigned	framesz;
1480 	unsigned	slen, flen;
1481 
1482 	if (auclnt_get_oflag(c) & FWRITE) {
1483 		audio_stream_t	*sp = auclnt_output_stream(c);
1484 		framesz = auclnt_get_framesz(sp);
1485 		auclnt_get_output_qlen(c, &slen, &flen);
1486 		*bytes = (slen + flen) * framesz;
1487 	} else {
1488 		*bytes = 0;
1489 	}
1490 	return (0);
1491 }
1492 
1493 static int
1494 sndctl_dsp_current_iptr(audio_client_t *c, oss_count_t *count)
1495 {
1496 	if (auclnt_get_oflag(c) & FREAD) {
1497 		count->samples = auclnt_get_samples(auclnt_input_stream(c));
1498 		count->fifo_samples = 0;	/* not quite accurate */
1499 	} else {
1500 		count->samples = 0;
1501 		count->fifo_samples = 0;
1502 	}
1503 	return (0);
1504 }
1505 
1506 static int
1507 sndctl_dsp_current_optr(audio_client_t *c, oss_count_t *count)
1508 {
1509 	unsigned samples, fifo;
1510 
1511 	if (auclnt_get_oflag(c) & FWRITE) {
1512 		auclnt_get_output_qlen(c, &samples, &fifo);
1513 		count->samples = samples;
1514 		count->fifo_samples = fifo;
1515 	} else {
1516 		count->samples = 0;
1517 		count->fifo_samples = 0;
1518 	}
1519 	return (0);
1520 }
1521 
1522 static int
1523 sndctl_dsp_getoptr(audio_client_t *c, count_info *ci)
1524 {
1525 	audio_stream_t	*sp;
1526 	unsigned	framesz;
1527 	unsigned	fragsz;
1528 
1529 	bzero(ci, sizeof (*ci));
1530 	if ((auclnt_get_oflag(c) & FWRITE) == 0) {
1531 		return (0);
1532 	}
1533 	sp = auclnt_output_stream(c);
1534 	framesz = auclnt_get_framesz(sp);
1535 	fragsz = auclnt_get_fragsz(sp);
1536 	ci->blocks = auclnt_get_samples(sp) * framesz / fragsz;
1537 	auclnt_set_samples(sp, 0);
1538 	ci->bytes = auclnt_get_tail(sp) * framesz;
1539 	ci->ptr = auclnt_get_tidx(sp) * framesz;
1540 	return (0);
1541 }
1542 
1543 static int
1544 sndctl_dsp_getiptr(audio_client_t *c, count_info *ci)
1545 {
1546 	audio_stream_t	*sp;
1547 	unsigned	framesz;
1548 	unsigned	fragsz;
1549 
1550 	bzero(ci, sizeof (*ci));
1551 	if ((auclnt_get_oflag(c) & FREAD) == 0) {
1552 		return (0);
1553 	}
1554 	sp = auclnt_input_stream(c);
1555 	framesz = auclnt_get_framesz(sp);
1556 	fragsz = auclnt_get_fragsz(sp);
1557 	ci->blocks = auclnt_get_samples(sp) * framesz / fragsz;
1558 	auclnt_set_samples(sp, 0);
1559 	ci->bytes = auclnt_get_head(sp) * framesz;
1560 	ci->ptr = auclnt_get_hidx(sp) * framesz;
1561 	return (0);
1562 }
1563 
1564 static int
1565 sndctl_dsp_geterror(audio_client_t *c, audio_errinfo *bi)
1566 {
1567 	audio_stream_t	*sp;
1568 	unsigned	fragsz;
1569 	/*
1570 	 * Note: The use of this structure is unsafe... different
1571 	 * meanings for error codes are used by different implementations,
1572 	 * according to the spec.  (Even different versions of the same
1573 	 * implementation could have different values.)
1574 	 *
1575 	 * Rather than try to come up with a reliable solution here, we
1576 	 * don't use it.  If you want to report errors, or see the result
1577 	 * of errors, use syslog.
1578 	 */
1579 	bzero(bi, sizeof (*bi));
1580 
1581 	sp = auclnt_output_stream(c);
1582 	fragsz = max(auclnt_get_fragsz(sp), 1);
1583 	bi->play_underruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) /
1584 	    fragsz);
1585 	auclnt_set_errors(sp, 0);
1586 
1587 	sp = auclnt_input_stream(c);
1588 	fragsz = max(auclnt_get_fragsz(sp), 1);
1589 	bi->rec_overruns = (int)((auclnt_get_errors(sp) + (fragsz - 1)) /
1590 	    fragsz);
1591 	auclnt_set_errors(sp, 0);
1592 
1593 	return (0);
1594 }
1595 
1596 static int
1597 sndctl_sun_send_number(audio_client_t *c, int *num, cred_t *cr)
1598 {
1599 	audio_dev_t	*dev;
1600 	int		rv;
1601 
1602 	if ((rv = drv_priv(cr)) != 0) {
1603 		return (rv);
1604 	}
1605 
1606 	dev = auclnt_get_dev(c);
1607 	auclnt_set_dev_number(dev, *num);
1608 	return (0);
1609 }
1610 
1611 static int
1612 oss_getversion(int *versp)
1613 {
1614 	*versp = OSS_VERSION;
1615 	return (0);
1616 }
1617 
1618 static int
1619 oss_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp,
1620     int *rvalp)
1621 {
1622 	int	sz;
1623 	void	*data;
1624 	int	rv = 0;
1625 
1626 	_NOTE(ARGUNUSED(credp));
1627 
1628 	sz = OSSIOC_GETSZ(cmd);
1629 
1630 	if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) {
1631 		if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) {
1632 			return (ENOMEM);
1633 		}
1634 	} else {
1635 		sz = 0;
1636 	}
1637 
1638 	if (cmd & OSSIOC_IN) {
1639 		if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) {
1640 			goto done;
1641 		}
1642 	}
1643 
1644 	switch (cmd) {
1645 		/*
1646 		 * DSP specific ioctls
1647 		 */
1648 	case SNDCTL_DSP_HALT:
1649 		rv = sndctl_dsp_halt(c);
1650 		break;
1651 
1652 	case SNDCTL_DSP_SYNC:
1653 		rv = sndctl_dsp_sync(c);
1654 		break;
1655 
1656 	case SNDCTL_DSP_SPEED:
1657 		rv = sndctl_dsp_speed(c, (int *)data);
1658 		break;
1659 	case SNDCTL_DSP_SETFMT:
1660 		rv = sndctl_dsp_setfmt(c, (int *)data);
1661 		break;
1662 	case SNDCTL_DSP_GETFMTS:
1663 		rv = sndctl_dsp_getfmts(c, (int *)data);
1664 		break;
1665 	case SNDCTL_DSP_STEREO:
1666 		rv = sndctl_dsp_stereo(c, (int *)data);
1667 		break;
1668 	case SNDCTL_DSP_CHANNELS:
1669 		rv = sndctl_dsp_channels(c, (int *)data);
1670 		break;
1671 	case SNDCTL_DSP_POST:
1672 		rv = sndctl_dsp_post(c);
1673 		break;
1674 	case SNDCTL_DSP_GETCAPS:
1675 		rv = sndctl_dsp_getcaps(c, (int *)data);
1676 		break;
1677 	case SNDCTL_DSP_GETTRIGGER:
1678 		rv = sndctl_dsp_gettrigger(c, (int *)data);
1679 		break;
1680 	case SNDCTL_DSP_SETTRIGGER:
1681 		rv = sndctl_dsp_settrigger(c, (int *)data);
1682 		break;
1683 	case SNDCTL_DSP_GETPLAYVOL:
1684 	case SOUND_MIXER_READ_VOLUME:	/* legacy mixer on dsp */
1685 	case SOUND_MIXER_READ_PCM:	/* legacy mixer on dsp */
1686 	case SOUND_MIXER_READ_OGAIN:	/* legacy mixer on dsp */
1687 		rv = sndctl_dsp_getplayvol(c, (int *)data);
1688 		break;
1689 	case SOUND_MIXER_WRITE_VOLUME:	/* legacy mixer on dsp */
1690 	case SOUND_MIXER_WRITE_PCM:	/* legacy mixer on dsp */
1691 	case SOUND_MIXER_WRITE_OGAIN:	/* legacy mixer on dsp */
1692 		rv = sound_mixer_write_ogain(c, (int *)data);
1693 		break;
1694 	case SNDCTL_DSP_SETPLAYVOL:
1695 		rv = sndctl_dsp_setplayvol(c, (int *)data);
1696 		break;
1697 	case SNDCTL_DSP_READCTL:
1698 		rv = sndctl_dsp_readctl(c, (oss_digital_control *)data);
1699 		break;
1700 	case SNDCTL_DSP_WRITECTL:
1701 		rv = sndctl_dsp_writectl(c, (oss_digital_control *)data);
1702 		break;
1703 	case SNDCTL_DSP_COOKEDMODE:
1704 		rv = sndctl_dsp_cookedmode(c, (int *)data);
1705 		break;
1706 	case SNDCTL_DSP_SILENCE:
1707 		rv = sndctl_dsp_silence(c);
1708 		break;
1709 	case SNDCTL_DSP_SKIP:
1710 		rv = sndctl_dsp_skip(c);
1711 		break;
1712 	case SNDCTL_DSP_HALT_INPUT:
1713 		rv = sndctl_dsp_halt_input(c);
1714 		break;
1715 	case SNDCTL_DSP_HALT_OUTPUT:
1716 		rv = sndctl_dsp_halt_output(c);
1717 		break;
1718 	case SNDCTL_DSP_GET_RECSRC_NAMES:
1719 		rv = sndctl_dsp_get_recsrc_names(c, (oss_mixer_enuminfo *)data);
1720 		break;
1721 	case SNDCTL_DSP_SUBDIVIDE:
1722 	case SNDCTL_DSP_SETFRAGMENT:
1723 		rv = sndctl_dsp_setfragment(c, (int *)data);
1724 		break;
1725 	case SNDCTL_DSP_GET_RECSRC:
1726 		rv = sndctl_dsp_get_recsrc(c, (int *)data);
1727 		break;
1728 	case SNDCTL_DSP_SET_RECSRC:
1729 		rv = sndctl_dsp_set_recsrc(c, (int *)data);
1730 		break;
1731 	case SNDCTL_DSP_GET_PLAYTGT_NAMES:
1732 		rv = sndctl_dsp_get_playtgt_names(c,
1733 		    (oss_mixer_enuminfo *)data);
1734 		break;
1735 	case SNDCTL_DSP_GET_PLAYTGT:
1736 		rv = sndctl_dsp_get_playtgt(c, (int *)data);
1737 		break;
1738 	case SNDCTL_DSP_SET_PLAYTGT:
1739 		rv = sndctl_dsp_set_playtgt(c, (int *)data);
1740 		break;
1741 	case SNDCTL_DSP_GETRECVOL:
1742 	case SOUND_MIXER_READ_RECGAIN:	/* legacy mixer on dsp */
1743 	case SOUND_MIXER_READ_RECLEV:	/* legacy mixer on dsp */
1744 	case SOUND_MIXER_READ_IGAIN:	/* legacy mixer on dsp */
1745 		rv = sndctl_dsp_getrecvol(c, (int *)data);
1746 		break;
1747 	case SOUND_MIXER_WRITE_RECGAIN:	/* legacy mixer on dsp */
1748 	case SOUND_MIXER_WRITE_RECLEV:	/* legacy mixer on dsp */
1749 	case SOUND_MIXER_WRITE_IGAIN:	/* legacy mixer on dsp */
1750 		rv = sound_mixer_write_igain(c, (int *)data);
1751 		break;
1752 	case SNDCTL_DSP_SETRECVOL:
1753 		rv = sndctl_dsp_setrecvol(c, (int *)data);
1754 		break;
1755 	case SNDCTL_DSP_SETDUPLEX:	/* Ignored */
1756 	case SNDCTL_DSP_LOW_WATER:	/* Ignored */
1757 	case SNDCTL_DSP_POLICY:		/* Ignored */
1758 	case SNDCTL_DSP_PROFILE:	/* Ignored */
1759 		rv = 0;
1760 		break;
1761 	case SNDCTL_DSP_GETBLKSIZE:
1762 		rv = sndctl_dsp_getblksize(c, (int *)data);
1763 		break;
1764 	case SNDCTL_DSP_GETOSPACE:
1765 		rv = sndctl_dsp_getospace(c, (audio_buf_info *)data);
1766 		break;
1767 	case SNDCTL_DSP_GETISPACE:
1768 		rv = sndctl_dsp_getispace(c, (audio_buf_info *)data);
1769 		break;
1770 	case SNDCTL_DSP_GETODELAY:
1771 		rv = sndctl_dsp_getodelay(c, (int *)data);
1772 		break;
1773 	case SNDCTL_DSP_GETOPTR:
1774 		rv = sndctl_dsp_getoptr(c, (count_info *)data);
1775 		break;
1776 	case SNDCTL_DSP_GETIPTR:
1777 		rv = sndctl_dsp_getiptr(c, (count_info *)data);
1778 		break;
1779 	case SNDCTL_DSP_GETERROR:
1780 		rv = sndctl_dsp_geterror(c, (audio_errinfo *)data);
1781 		break;
1782 	case SNDCTL_DSP_CURRENT_IPTR:
1783 		rv = sndctl_dsp_current_iptr(c, (oss_count_t *)data);
1784 		break;
1785 	case SNDCTL_DSP_CURRENT_OPTR:
1786 		rv = sndctl_dsp_current_optr(c, (oss_count_t *)data);
1787 		break;
1788 
1789 		/*
1790 		 * Shared ioctls with /dev/mixer.
1791 		 */
1792 	case OSS_GETVERSION:
1793 		rv = oss_getversion((int *)data);
1794 		break;
1795 	case SNDCTL_CARDINFO:
1796 		rv = sndctl_cardinfo(c, (oss_card_info *)data);
1797 		break;
1798 	case SNDCTL_ENGINEINFO:
1799 	case SNDCTL_AUDIOINFO:
1800 	case SNDCTL_AUDIOINFO_EX:
1801 		rv = sndctl_audioinfo(c, (oss_audioinfo *)data);
1802 		break;
1803 	case SNDCTL_SYSINFO:
1804 		rv = sndctl_sysinfo((oss_sysinfo *)data);
1805 		break;
1806 	case SNDCTL_MIXERINFO:
1807 		rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data);
1808 		break;
1809 	case SOUND_MIXER_INFO:
1810 		rv = sound_mixer_info(c, (mixer_info *)data);
1811 		break;
1812 
1813 		/*
1814 		 * These are mixer ioctls that are virtualized for the DSP
1815 		 * device.  They are accessible via either /dev/mixer or
1816 		 * /dev/dsp.
1817 		 */
1818 	case SOUND_MIXER_READ_RECSRC:
1819 	case SOUND_MIXER_WRITE_RECSRC:
1820 		rv = sound_mixer_read_recsrc(c, (int *)data);
1821 		break;
1822 
1823 	case SOUND_MIXER_READ_DEVMASK:
1824 	case SOUND_MIXER_READ_STEREODEVS:
1825 		rv = sound_mixer_read_devmask(c, (int *)data);
1826 		break;
1827 
1828 	case SOUND_MIXER_READ_RECMASK:
1829 		rv = sound_mixer_read_recmask(c, (int *)data);
1830 		break;
1831 
1832 	case SOUND_MIXER_READ_CAPS:
1833 		rv = sound_mixer_read_caps(c, (int *)data);
1834 		break;
1835 
1836 		/*
1837 		 * Ioctls we have chosen not to support for now.  Some
1838 		 * of these are of legacy interest only.
1839 		 */
1840 	case SNDCTL_SETSONG:
1841 	case SNDCTL_GETSONG:
1842 	case SNDCTL_DSP_SYNCGROUP:
1843 	case SNDCTL_DSP_SYNCSTART:
1844 	case SNDCTL_DSP_GET_CHNORDER:
1845 	case SNDCTL_DSP_SET_CHNORDER:
1846 	case SNDCTL_DSP_GETIPEAKS:
1847 	case SNDCTL_DSP_GETOPEAKS:
1848 	case SNDCTL_DSP_GETCHANNELMASK:
1849 	case SNDCTL_DSP_BIND_CHANNEL:
1850 	case SNDCTL_DSP_SETSYNCRO:
1851 	default:
1852 		rv = EINVAL;
1853 		break;
1854 	}
1855 
1856 	if ((rv == 0) && (cmd & OSSIOC_OUT)) {
1857 		rv = ddi_copyout(data, (void *)arg, sz, mode);
1858 	}
1859 	if (rv == 0) {
1860 		*rvalp = 0;
1861 	}
1862 
1863 done:
1864 	if (sz) {
1865 		kmem_free(data, sz);
1866 	}
1867 	return (rv);
1868 }
1869 
1870 static void
1871 oss_output(audio_client_t *c)
1872 {
1873 	auclnt_pollwakeup(c, POLLOUT);
1874 }
1875 
1876 static void
1877 oss_input(audio_client_t *c)
1878 {
1879 	auclnt_pollwakeup(c, POLLIN | POLLRDNORM);
1880 }
1881 
1882 static void
1883 oss_notify(audio_client_t *c)
1884 {
1885 	audio_dev_t	*d;
1886 	ossdev_t	*odev;
1887 
1888 	d = auclnt_get_dev(c);
1889 	if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) {
1890 		return;
1891 	}
1892 	odev->d_modify_cnt++;
1893 }
1894 
1895 static int
1896 ossmix_open(audio_client_t *c, int oflag)
1897 {
1898 	int		rv;
1899 	ossclient_t	*sc;
1900 	ossdev_t	*odev;
1901 
1902 	_NOTE(ARGUNUSED(oflag));
1903 
1904 	if ((rv = auclnt_open(c, AUDIO_FORMAT_NONE, 0)) != 0) {
1905 		return (rv);
1906 	}
1907 
1908 	if ((sc = kmem_zalloc(sizeof (*sc), KM_NOSLEEP)) == NULL) {
1909 		return (ENOMEM);
1910 	}
1911 	sc->o_ss_sz = 8192;
1912 	if ((sc->o_ss_buf = kmem_zalloc(sc->o_ss_sz, KM_NOSLEEP)) == NULL) {
1913 		kmem_free(sc, sizeof (*sc));
1914 		return (ENOMEM);
1915 	}
1916 	auclnt_set_private(c, sc);
1917 
1918 	odev = auclnt_get_minor_data(c, AUDIO_MINOR_DSP);
1919 
1920 	/* set a couple of common fields */
1921 	sc->o_client = c;
1922 	sc->o_ossdev = odev;
1923 
1924 	return (rv);
1925 }
1926 
1927 static void
1928 ossmix_close(audio_client_t *c)
1929 {
1930 	ossclient_t	*sc;
1931 
1932 	sc = auclnt_get_private(c);
1933 
1934 	kmem_free(sc->o_ss_buf, sc->o_ss_sz);
1935 	kmem_free(sc, sizeof (*sc));
1936 
1937 	auclnt_close(c);
1938 }
1939 
1940 static int
1941 sndctl_mix_nrext(audio_client_t *c, int *ncp)
1942 {
1943 	audio_dev_t	*d;
1944 	ossdev_t	*odev;
1945 
1946 	d = auclnt_get_dev(c);
1947 
1948 	if ((*ncp != -1) && (*ncp != (auclnt_get_dev_index(d) - 1))) {
1949 		return (ENXIO);
1950 	}
1951 
1952 	if ((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) {
1953 		return (EINVAL);
1954 	}
1955 
1956 	*ncp = odev->d_nctrl;
1957 
1958 	return (0);
1959 }
1960 
1961 static int
1962 sndctl_mix_extinfo(audio_client_t *c, oss_mixext *pext)
1963 {
1964 	audio_dev_t		*d;
1965 	ossdev_t		*odev;
1966 	int			rv = 0;
1967 	int			dev;
1968 
1969 	d = auclnt_get_dev(c);
1970 
1971 	if (((dev = pext->dev) != -1) && (dev != (auclnt_get_dev_index(d) - 1)))
1972 		return (ENXIO);
1973 
1974 	if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
1975 	    (pext->ctrl >= odev->d_nctrl)) {
1976 		return (EINVAL);
1977 	}
1978 
1979 	bcopy(&odev->d_exts[pext->ctrl], pext, sizeof (*pext));
1980 	pext->enumbit = 0;
1981 	pext->dev = dev;
1982 
1983 	return (rv);
1984 }
1985 
1986 static int
1987 sndctl_mix_enuminfo(audio_client_t *c, oss_mixer_enuminfo *ei)
1988 {
1989 	audio_dev_t		*d;
1990 	audio_ctrl_desc_t	desc;
1991 	audio_ctrl_t		*ctrl;
1992 	ossdev_t		*odev;
1993 	uint64_t		mask;
1994 	int			bit;
1995 	ushort_t		nxt;
1996 
1997 	d = auclnt_get_dev(c);
1998 
1999 	if ((ei->dev != -1) && (ei->dev != (auclnt_get_dev_index(d) - 1)))
2000 		return (ENXIO);
2001 
2002 	if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
2003 	    (ei->ctrl >= odev->d_nctrl) ||
2004 	    (odev->d_exts[ei->ctrl].type != MIXT_ENUM) ||
2005 	    ((ctrl = odev->d_ctrls[ei->ctrl]) == NULL) ||
2006 	    (auclnt_control_describe(ctrl, &desc) != 0)) {
2007 		return (EINVAL);
2008 	}
2009 
2010 	mask = desc.acd_maxvalue;
2011 	bit = 0;
2012 	nxt = 0;
2013 	ei->nvalues = 0;
2014 	bzero(ei->strings, sizeof (ei->strings));
2015 	bzero(ei->strindex, sizeof (ei->strindex));
2016 
2017 	while (mask) {
2018 		const char *name = desc.acd_enum[bit];
2019 		nxt = oss_set_enum(ei, nxt, name ? name : "");
2020 		mask >>= 1;
2021 		bit++;
2022 	}
2023 
2024 	return (0);
2025 }
2026 
2027 static int
2028 sndctl_mix_read(audio_client_t *c, oss_mixer_value *vr)
2029 {
2030 	int			rv;
2031 	uint64_t		v;
2032 	audio_dev_t		*d;
2033 	audio_ctrl_t		*ctrl;
2034 	ossdev_t		*odev;
2035 
2036 	d = auclnt_get_dev(c);
2037 
2038 	if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1)))
2039 		return (ENXIO);
2040 
2041 	if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
2042 	    (vr->ctrl >= odev->d_nctrl) ||
2043 	    ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) {
2044 		return (EINVAL);
2045 	}
2046 	if ((rv = auclnt_control_read(ctrl, &v)) == 0) {
2047 		switch (odev->d_exts[vr->ctrl].type) {
2048 		case MIXT_ENUM:
2049 			/* translate this from an enum style bit mask */
2050 			vr->value = ddi_ffs((unsigned long)v) - 1;
2051 			break;
2052 		case MIXT_STEREOSLIDER:
2053 			vr->value = (int)ddi_swap16(v & 0xffff);
2054 			break;
2055 		case MIXT_MONOSLIDER:
2056 			vr->value = (int)(v | (v << 8));
2057 			break;
2058 		case MIXT_ONOFF:
2059 			/* this could be simple, or could be part of a multi */
2060 			if (odev->d_exts[vr->ctrl].enumbit >= 0) {
2061 				uint64_t mask;
2062 				mask = 1;
2063 				mask <<= (odev->d_exts[vr->ctrl].enumbit);
2064 				vr->value = (v & mask) ? 1 : 0;
2065 			} else {
2066 				vr->value = v ? 1 : 0;
2067 			}
2068 			break;
2069 
2070 		default:
2071 			vr->value = (int)v;
2072 			break;
2073 		}
2074 	}
2075 
2076 	return (rv);
2077 }
2078 
2079 static int
2080 sndctl_mix_write(audio_client_t *c, oss_mixer_value *vr)
2081 {
2082 	int			rv;
2083 	uint64_t		v;
2084 	audio_dev_t		*d;
2085 	audio_ctrl_t		*ctrl;
2086 	ossdev_t		*odev;
2087 
2088 	d = auclnt_get_dev(c);
2089 
2090 	if ((vr->dev != -1) && (vr->dev != (auclnt_get_dev_index(d) - 1)))
2091 		return (ENXIO);
2092 
2093 	if (((odev = auclnt_get_dev_minor_data(d, AUDIO_MINOR_DSP)) == NULL) ||
2094 	    (vr->ctrl >= odev->d_nctrl) ||
2095 	    ((ctrl = odev->d_ctrls[vr->ctrl]) == NULL)) {
2096 		return (EINVAL);
2097 	}
2098 
2099 	switch (odev->d_exts[vr->ctrl].type) {
2100 	case MIXT_ONOFF:
2101 		/* this could be standalone, or it could be part of a multi */
2102 		if (odev->d_exts[vr->ctrl].enumbit >= 0) {
2103 			uint64_t mask;
2104 			if ((rv = auclnt_control_read(ctrl, &v)) != 0) {
2105 				return (EINVAL);
2106 			}
2107 			mask = 1;
2108 			mask <<= (odev->d_exts[vr->ctrl].enumbit);
2109 			if (vr->value) {
2110 				v |= mask;
2111 			} else {
2112 				v &= ~mask;
2113 			}
2114 		} else {
2115 			v = vr->value;
2116 		}
2117 		break;
2118 	case MIXT_ENUM:
2119 		/* translate this to an enum style bit mask */
2120 		v = 1U << vr->value;
2121 		break;
2122 	case MIXT_MONOSLIDER:
2123 		/* mask off high order bits */
2124 		v = vr->value & 0xff;
2125 		break;
2126 	case MIXT_STEREOSLIDER:
2127 		/* OSS uses reverse byte ordering */
2128 		v = vr->value;
2129 		v = ddi_swap16(vr->value & 0xffff);
2130 		break;
2131 	default:
2132 		v = vr->value;
2133 	}
2134 	rv = auclnt_control_write(ctrl, v);
2135 
2136 	return (rv);
2137 }
2138 
2139 static int
2140 sndctl_mix_nrmix(audio_client_t *c, int *nmixp)
2141 {
2142 	_NOTE(ARGUNUSED(c));
2143 	*nmixp = oss_cnt_devs() - 1;
2144 	return (0);
2145 }
2146 
2147 static int
2148 ossmix_ioctl(audio_client_t *c, int cmd, intptr_t arg, int mode, cred_t *credp,
2149     int *rvalp)
2150 {
2151 	int	sz;
2152 	void	*data;
2153 	int	rv = 0;
2154 
2155 	sz = OSSIOC_GETSZ(cmd);
2156 
2157 	if ((cmd & (OSSIOC_IN | OSSIOC_OUT)) && sz) {
2158 		if ((data = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) {
2159 			return (ENOMEM);
2160 		}
2161 	} else {
2162 		sz = 0;
2163 	}
2164 
2165 	if (cmd & OSSIOC_IN) {
2166 		if ((rv = ddi_copyin((void *)arg, data, sz, mode)) != 0) {
2167 			goto done;
2168 		}
2169 	}
2170 
2171 	switch (cmd) {
2172 		/*
2173 		 * Mixer specific ioctls
2174 		 */
2175 	case SNDCTL_MIX_NREXT:
2176 		rv = sndctl_mix_nrext(c, (int *)data);
2177 		break;
2178 	case SNDCTL_MIX_EXTINFO:
2179 		rv = sndctl_mix_extinfo(c, (oss_mixext *)data);
2180 		break;
2181 	case SNDCTL_MIX_ENUMINFO:
2182 		rv = sndctl_mix_enuminfo(c, (oss_mixer_enuminfo *)data);
2183 		break;
2184 	case SNDCTL_MIX_READ:
2185 		rv = sndctl_mix_read(c, (oss_mixer_value *)data);
2186 		break;
2187 	case SNDCTL_MIX_WRITE:
2188 		rv = sndctl_mix_write(c, (oss_mixer_value *)data);
2189 		break;
2190 	case SNDCTL_MIX_NRMIX:
2191 		rv = sndctl_mix_nrmix(c, (int *)data);
2192 		break;
2193 
2194 		/*
2195 		 * Legacy ioctls.  These are treated as soft values only,
2196 		 * and do not affect global hardware state.  For use by
2197 		 * legacy DSP applications.
2198 		 */
2199 	case SOUND_MIXER_READ_VOLUME:
2200 	case SOUND_MIXER_READ_PCM:
2201 	case SOUND_MIXER_READ_OGAIN:
2202 		rv = sndctl_dsp_getplayvol(c, (int *)data);
2203 		break;
2204 
2205 	case SOUND_MIXER_WRITE_VOLUME:
2206 	case SOUND_MIXER_WRITE_PCM:
2207 	case SOUND_MIXER_WRITE_OGAIN:
2208 		rv = sound_mixer_write_ogain(c, (int *)data);
2209 		break;
2210 
2211 	case SOUND_MIXER_READ_RECGAIN:
2212 	case SOUND_MIXER_READ_RECLEV:
2213 	case SOUND_MIXER_READ_IGAIN:
2214 		rv = sndctl_dsp_getrecvol(c, (int *)data);
2215 		break;
2216 
2217 	case SOUND_MIXER_WRITE_RECGAIN:
2218 	case SOUND_MIXER_WRITE_RECLEV:
2219 	case SOUND_MIXER_WRITE_IGAIN:
2220 		rv = sound_mixer_write_igain(c, (int *)data);
2221 		break;
2222 
2223 	case SOUND_MIXER_READ_RECSRC:
2224 	case SOUND_MIXER_WRITE_RECSRC:
2225 		rv = sound_mixer_read_recsrc(c, (int *)data);
2226 		break;
2227 
2228 	case SOUND_MIXER_READ_DEVMASK:
2229 	case SOUND_MIXER_READ_STEREODEVS:
2230 		rv = sound_mixer_read_devmask(c, (int *)data);
2231 		break;
2232 
2233 	case SOUND_MIXER_READ_RECMASK:
2234 		rv = sound_mixer_read_recmask(c, (int *)data);
2235 		break;
2236 
2237 		/*
2238 		 * Common ioctls shared with DSP
2239 		 */
2240 	case OSS_GETVERSION:
2241 		rv = oss_getversion((int *)data);
2242 		break;
2243 
2244 	case SNDCTL_CARDINFO:
2245 		rv = sndctl_cardinfo(c, (oss_card_info *)data);
2246 		break;
2247 
2248 	case SNDCTL_ENGINEINFO:
2249 	case SNDCTL_AUDIOINFO:
2250 	case SNDCTL_AUDIOINFO_EX:
2251 		rv = sndctl_audioinfo(c, (oss_audioinfo *)data);
2252 		break;
2253 
2254 	case SNDCTL_SYSINFO:
2255 		rv = sndctl_sysinfo((oss_sysinfo *)data);
2256 		break;
2257 
2258 	case SNDCTL_MIXERINFO:
2259 		rv = sndctl_mixerinfo(c, (oss_mixerinfo *)data);
2260 		break;
2261 
2262 	case SOUND_MIXER_INFO:
2263 		rv = sound_mixer_info(c, (mixer_info *)data);
2264 		break;
2265 
2266 	case SNDCTL_MIX_DESCRIPTION:	/* NOT SUPPORTED: tooltip */
2267 		rv = EIO;	/* OSS returns EIO for this one */
2268 		break;
2269 
2270 		/*
2271 		 * Special implementation-private ioctls.
2272 		 */
2273 	case SNDCTL_SUN_SEND_NUMBER:
2274 		rv = sndctl_sun_send_number(c, (int *)data, credp);
2275 		break;
2276 
2277 		/*
2278 		 * Legacy ioctls we don't support.
2279 		 */
2280 	case SOUND_MIXER_WRITE_MONGAIN:
2281 	case SOUND_MIXER_READ_MONGAIN:
2282 	case SOUND_MIXER_READ_BASS:
2283 	case SOUND_MIXER_READ_TREBLE:
2284 	case SOUND_MIXER_READ_SPEAKER:
2285 	case SOUND_MIXER_READ_LINE:
2286 	case SOUND_MIXER_READ_MIC:
2287 	case SOUND_MIXER_READ_CD:
2288 	case SOUND_MIXER_READ_IMIX:
2289 	case SOUND_MIXER_READ_ALTPCM:
2290 	case SOUND_MIXER_READ_SYNTH:
2291 	case SOUND_MIXER_READ_LINE1:
2292 	case SOUND_MIXER_READ_LINE2:
2293 	case SOUND_MIXER_READ_LINE3:
2294 	case SOUND_MIXER_WRITE_BASS:
2295 	case SOUND_MIXER_WRITE_TREBLE:
2296 	case SOUND_MIXER_WRITE_SPEAKER:
2297 	case SOUND_MIXER_WRITE_LINE:
2298 	case SOUND_MIXER_WRITE_MIC:
2299 	case SOUND_MIXER_WRITE_CD:
2300 	case SOUND_MIXER_WRITE_IMIX:
2301 	case SOUND_MIXER_WRITE_ALTPCM:
2302 	case SOUND_MIXER_WRITE_SYNTH:
2303 	case SOUND_MIXER_WRITE_LINE1:
2304 	case SOUND_MIXER_WRITE_LINE2:
2305 	case SOUND_MIXER_WRITE_LINE3:
2306 		/*
2307 		 * Additional ioctls we *could* support, but don't.
2308 		 */
2309 	case SNDCTL_SETSONG:
2310 	case SNDCTL_SETLABEL:
2311 	case SNDCTL_GETSONG:
2312 	case SNDCTL_GETLABEL:
2313 	case SNDCTL_MIDIINFO:
2314 	case SNDCTL_SETNAME:
2315 	default:
2316 		rv = EINVAL;
2317 		break;
2318 	}
2319 
2320 	if ((rv == 0) && (cmd & OSSIOC_OUT)) {
2321 		rv = ddi_copyout(data, (void *)arg, sz, mode);
2322 	}
2323 	if (rv == 0) {
2324 		*rvalp = 0;
2325 	}
2326 
2327 done:
2328 	if (sz) {
2329 		kmem_free(data, sz);
2330 	}
2331 	return (rv);
2332 }
2333 
2334 static void *
2335 oss_dev_init(audio_dev_t *dev)
2336 {
2337 	ossdev_t	*odev;
2338 
2339 	odev = kmem_zalloc(sizeof (*odev), KM_SLEEP);
2340 	odev->d_dev = dev;
2341 
2342 	mutex_init(&odev->d_mx, NULL, MUTEX_DRIVER, NULL);
2343 	cv_init(&odev->d_cv, NULL, CV_DRIVER, NULL);
2344 	oss_alloc_controls(odev);
2345 
2346 	return (odev);
2347 }
2348 
2349 static void
2350 oss_dev_fini(void *arg)
2351 {
2352 	ossdev_t	*odev = arg;
2353 
2354 	if (odev != NULL) {
2355 		oss_free_controls(odev);
2356 		mutex_destroy(&odev->d_mx);
2357 		cv_destroy(&odev->d_cv);
2358 		kmem_free(odev, sizeof (*odev));
2359 	}
2360 }
2361 
2362 static void
2363 sndstat_printf(ossclient_t *oc, const char *fmt, ...)
2364 {
2365 	va_list	va;
2366 
2367 	va_start(va, fmt);
2368 	(void) vsnprintf(oc->o_ss_buf + oc->o_ss_len,
2369 	    oc->o_ss_sz - oc->o_ss_len, fmt, va);
2370 	va_end(va);
2371 	oc->o_ss_len = strlen(oc->o_ss_buf);
2372 }
2373 
2374 static int
2375 sndstat_dev_walker(audio_dev_t *d, void *arg)
2376 {
2377 	ossclient_t	*oc = arg;
2378 	const char	*capstr;
2379 	unsigned	cap;
2380 
2381 	cap = auclnt_get_dev_capab(d);
2382 
2383 	if (cap	& AUDIO_CLIENT_CAP_DUPLEX) {
2384 		capstr = "DUPLEX";
2385 	} else if ((cap & AUDIO_CLIENT_CAP_PLAY) &&
2386 	    (cap & AUDIO_CLIENT_CAP_RECORD)) {
2387 		capstr = "INPUT,OUTPUT";
2388 	} else if (cap & AUDIO_CLIENT_CAP_PLAY) {
2389 		capstr = "OUTPUT";
2390 	} else if (cap & AUDIO_CLIENT_CAP_RECORD) {
2391 		capstr = "INPUT";
2392 	} else {
2393 		capstr = NULL;
2394 	}
2395 
2396 	if (capstr == NULL)
2397 		return (AUDIO_WALK_CONTINUE);
2398 
2399 	sndstat_printf(oc, "%d: %s %s, %s (%s)\n",
2400 	    auclnt_get_dev_number(d), auclnt_get_dev_name(d),
2401 	    auclnt_get_dev_description(d), auclnt_get_dev_version(d), capstr);
2402 
2403 	return (AUDIO_WALK_CONTINUE);
2404 }
2405 
2406 static int
2407 sndstat_mixer_walker(audio_dev_t *d, void *arg)
2408 {
2409 	ossclient_t	*oc = arg;
2410 	unsigned	cap;
2411 	void		*iter;
2412 	const char	*info;
2413 
2414 	cap = auclnt_get_dev_capab(d);
2415 
2416 	if ((cap & (AUDIO_CLIENT_CAP_PLAY|AUDIO_CLIENT_CAP_RECORD)) == 0)
2417 		return (AUDIO_WALK_CONTINUE);
2418 
2419 	sndstat_printf(oc, "%d: %s %s, %s\n",
2420 	    auclnt_get_dev_number(d), auclnt_get_dev_name(d),
2421 	    auclnt_get_dev_description(d), auclnt_get_dev_version(d));
2422 	iter = NULL;
2423 	while ((info = auclnt_get_dev_hw_info(d, &iter)) != NULL) {
2424 		sndstat_printf(oc, "\t%s\n", info);
2425 	}
2426 	return (AUDIO_WALK_CONTINUE);
2427 }
2428 
2429 static int
2430 ossmix_write(audio_client_t *c, struct uio *uio, cred_t *cr)
2431 {
2432 	/* write on sndstat is a no-op */
2433 	_NOTE(ARGUNUSED(c));
2434 	_NOTE(ARGUNUSED(uio));
2435 	_NOTE(ARGUNUSED(cr));
2436 
2437 	return (0);
2438 }
2439 
2440 static int
2441 ossmix_read(audio_client_t *c, struct uio *uio, cred_t *cr)
2442 {
2443 	ossclient_t	*oc;
2444 	unsigned	n;
2445 	int		rv;
2446 
2447 	_NOTE(ARGUNUSED(cr));
2448 
2449 	if (uio->uio_resid == 0) {
2450 		return (0);
2451 	}
2452 
2453 	oc = auclnt_get_private(c);
2454 
2455 	mutex_enter(&oc->o_ss_lock);
2456 
2457 	if (oc->o_ss_off == 0) {
2458 
2459 		sndstat_printf(oc, "SunOS Audio Framework\n");
2460 
2461 		sndstat_printf(oc, "\nAudio Devices:\n");
2462 		auclnt_walk_devs_by_number(sndstat_dev_walker, oc);
2463 
2464 		sndstat_printf(oc, "\nMixers:\n");
2465 		auclnt_walk_devs_by_number(sndstat_mixer_walker, oc);
2466 	}
2467 
2468 	/*
2469 	 * For simplicity's sake, we implement a non-seekable device.  We could
2470 	 * support seekability, but offsets would be rather meaningless between
2471 	 * changes.
2472 	 */
2473 	n = min(uio->uio_resid, (oc->o_ss_len - oc->o_ss_off));
2474 
2475 	rv = uiomove(oc->o_ss_buf + oc->o_ss_off, n, UIO_READ, uio);
2476 	if (rv != 0) {
2477 		n = 0;
2478 	}
2479 	oc->o_ss_off += n;
2480 
2481 	if (n == 0) {
2482 		/*
2483 		 * end-of-file reached... clear the sndstat buffer so that
2484 		 * subsequent reads will get the latest data.
2485 		 */
2486 		oc->o_ss_off = oc->o_ss_len = 0;
2487 	}
2488 	mutex_exit(&oc->o_ss_lock);
2489 	return (rv);
2490 }
2491 
2492 int
2493 oss_read(audio_client_t *c, struct uio *uio, cred_t *cr)
2494 {
2495 	_NOTE(ARGUNUSED(cr));
2496 
2497 	auclnt_clear_paused(auclnt_input_stream(c));
2498 
2499 	return (auclnt_read(c, uio));
2500 }
2501 
2502 int
2503 oss_write(audio_client_t *c, struct uio *uio, cred_t *cr)
2504 {
2505 	_NOTE(ARGUNUSED(cr));
2506 
2507 	auclnt_clear_paused(auclnt_output_stream(c));
2508 
2509 	return (auclnt_write(c, uio));
2510 }
2511 
2512 int
2513 oss_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp,
2514     struct pollhead **phpp)
2515 {
2516 	return (auclnt_chpoll(c, events, anyyet, reventsp, phpp));
2517 }
2518 
2519 static struct audio_client_ops oss_ops = {
2520 	"sound,dsp",
2521 	oss_dev_init,
2522 	oss_dev_fini,
2523 	oss_open,
2524 	oss_close,
2525 	oss_read,
2526 	oss_write,
2527 	oss_ioctl,
2528 	oss_chpoll,
2529 	NULL,		/* mmap */
2530 	oss_input,
2531 	oss_output,
2532 	NULL,		/* notify */
2533 	NULL,		/* drain */
2534 };
2535 
2536 static struct audio_client_ops ossmix_ops = {
2537 	"sound,mixer",
2538 	NULL,
2539 	NULL,
2540 	ossmix_open,
2541 	ossmix_close,
2542 	ossmix_read,
2543 	ossmix_write,
2544 	ossmix_ioctl,
2545 	NULL,	/* chpoll */
2546 	NULL,   /* mmap */
2547 	NULL,	/* input */
2548 	NULL,   /* output */
2549 	oss_notify,
2550 	NULL,	/* drain */
2551 };
2552 
2553 /* nearly the same as ossxmix; different minor name helps devfsadm */
2554 static struct audio_client_ops sndstat_ops = {
2555 	"sound,sndstat",
2556 	NULL,	/* dev_init */
2557 	NULL,	/* dev_fini */
2558 	ossmix_open,
2559 	ossmix_close,
2560 	ossmix_read,
2561 	ossmix_write,
2562 	ossmix_ioctl,
2563 	NULL,	/* chpoll */
2564 	NULL,	/* mmap */
2565 	NULL,	/* input */
2566 	NULL,	/* output */
2567 	NULL,	/* notify */
2568 	NULL,	/* drain */
2569 };
2570 
2571 void
2572 auimpl_oss_init(void)
2573 {
2574 	auclnt_register_ops(AUDIO_MINOR_DSP, &oss_ops);
2575 	auclnt_register_ops(AUDIO_MINOR_MIXER, &ossmix_ops);
2576 	auclnt_register_ops(AUDIO_MINOR_SNDSTAT, &sndstat_ops);
2577 }
2578