xref: /onnv-gate/usr/src/uts/common/io/audio/impl/audio_client.c (revision 12979:99d5baececdc)
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 /*
229484Sgarrett.damore@Sun.COM  * Copyright (C) 4Front Technologies 1996-2008.
239484Sgarrett.damore@Sun.COM  *
2412165Sgdamore@opensolaris.org  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
259484Sgarrett.damore@Sun.COM  */
269484Sgarrett.damore@Sun.COM 
279484Sgarrett.damore@Sun.COM #include <sys/types.h>
289484Sgarrett.damore@Sun.COM #include <sys/sysmacros.h>
299484Sgarrett.damore@Sun.COM #include <sys/list.h>
309484Sgarrett.damore@Sun.COM #include <sys/file.h>
319484Sgarrett.damore@Sun.COM #include <sys/open.h>
329484Sgarrett.damore@Sun.COM #include <sys/stat.h>
339484Sgarrett.damore@Sun.COM #include <sys/errno.h>
349484Sgarrett.damore@Sun.COM #include <sys/atomic.h>
359484Sgarrett.damore@Sun.COM #include <sys/ddi.h>
369484Sgarrett.damore@Sun.COM #include <sys/sunddi.h>
379484Sgarrett.damore@Sun.COM 
389484Sgarrett.damore@Sun.COM #include "audio_impl.h"
399484Sgarrett.damore@Sun.COM 
409484Sgarrett.damore@Sun.COM /*
419484Sgarrett.damore@Sun.COM  * Audio Client implementation.
429484Sgarrett.damore@Sun.COM  */
439484Sgarrett.damore@Sun.COM 
449484Sgarrett.damore@Sun.COM /*
459484Sgarrett.damore@Sun.COM  * Attenuation table for dB->linear conversion. Indexed in steps of
469484Sgarrett.damore@Sun.COM  * 0.5 dB.  Table size is 25 dB (first entry is handled as mute).
479484Sgarrett.damore@Sun.COM  *
489484Sgarrett.damore@Sun.COM  * Notably, the last item in table is taken as 0 dB (i.e. maximum volume).
499484Sgarrett.damore@Sun.COM  *
509484Sgarrett.damore@Sun.COM  * Table contents can be calculated as follows (requires sunmath library):
519484Sgarrett.damore@Sun.COM  *
529484Sgarrett.damore@Sun.COM  * scale = AUDIO_VOL_SCALE;
539484Sgarrett.damore@Sun.COM  * for (i = -50; i <= 0; i++) {
549484Sgarrett.damore@Sun.COM  *     x = exp10(0.05 * i);
559484Sgarrett.damore@Sun.COM  *     printf("%d: %f %.0f\n", i,  x, trunc(x * scale));
569484Sgarrett.damore@Sun.COM  * }
579484Sgarrett.damore@Sun.COM  *
589484Sgarrett.damore@Sun.COM  */
599484Sgarrett.damore@Sun.COM 
6010570Sgdamore@opensolaris.org static const uint16_t auimpl_db_table[AUDIO_DB_SIZE + 1] = {
619484Sgarrett.damore@Sun.COM 	0,   0,   1,   1,   1,   1,   1,   1,   2,   2,
629484Sgarrett.damore@Sun.COM 	2,   2,   3,   3,   4,   4,   5,   5,   6,   7,
639484Sgarrett.damore@Sun.COM 	8,   9,   10,  11,  12,  14,  16,  18,  20,  22,
649484Sgarrett.damore@Sun.COM 	25,  28,  32,  36,  40,  45,  51,  57,  64,  72,
659484Sgarrett.damore@Sun.COM 	80,  90,  101, 114, 128, 143, 161, 181, 203, 228,
669484Sgarrett.damore@Sun.COM 	256
679484Sgarrett.damore@Sun.COM };
689484Sgarrett.damore@Sun.COM 
6910570Sgdamore@opensolaris.org static list_t			auimpl_clients;
7010570Sgdamore@opensolaris.org static krwlock_t		auimpl_client_lock;
7110570Sgdamore@opensolaris.org static audio_client_ops_t	*audio_client_ops[AUDIO_MN_TYPE_MASK + 1];
7210570Sgdamore@opensolaris.org 
739484Sgarrett.damore@Sun.COM void *
auclnt_get_private(audio_client_t * c)749484Sgarrett.damore@Sun.COM auclnt_get_private(audio_client_t *c)
759484Sgarrett.damore@Sun.COM {
769484Sgarrett.damore@Sun.COM 	return (c->c_private);
779484Sgarrett.damore@Sun.COM }
789484Sgarrett.damore@Sun.COM 
799484Sgarrett.damore@Sun.COM void
auclnt_set_private(audio_client_t * c,void * private)809484Sgarrett.damore@Sun.COM auclnt_set_private(audio_client_t *c, void *private)
819484Sgarrett.damore@Sun.COM {
829484Sgarrett.damore@Sun.COM 	c->c_private = private;
839484Sgarrett.damore@Sun.COM }
849484Sgarrett.damore@Sun.COM 
859484Sgarrett.damore@Sun.COM int
auclnt_set_rate(audio_stream_t * sp,int rate)869484Sgarrett.damore@Sun.COM auclnt_set_rate(audio_stream_t *sp, int rate)
879484Sgarrett.damore@Sun.COM {
889484Sgarrett.damore@Sun.COM 	audio_parms_t	parms;
899484Sgarrett.damore@Sun.COM 	int		rv = 0;
909484Sgarrett.damore@Sun.COM 
919484Sgarrett.damore@Sun.COM 	/* basic sanity checks! */
929484Sgarrett.damore@Sun.COM 	if ((rate < 5000) || (rate > 192000)) {
939484Sgarrett.damore@Sun.COM 		return (EINVAL);
949484Sgarrett.damore@Sun.COM 	}
9512165Sgdamore@opensolaris.org 	if (rate != sp->s_user_parms->p_rate) {
969484Sgarrett.damore@Sun.COM 		parms.p_rate = rate;
9712165Sgdamore@opensolaris.org 		rv = auimpl_engine_setup(sp, 0, &parms, FORMAT_MSK_RATE);
989484Sgarrett.damore@Sun.COM 	}
999484Sgarrett.damore@Sun.COM 	return (rv);
1009484Sgarrett.damore@Sun.COM }
1019484Sgarrett.damore@Sun.COM 
1029484Sgarrett.damore@Sun.COM int
auclnt_get_rate(audio_stream_t * sp)1039484Sgarrett.damore@Sun.COM auclnt_get_rate(audio_stream_t *sp)
1049484Sgarrett.damore@Sun.COM {
1059484Sgarrett.damore@Sun.COM 	return (sp->s_user_parms->p_rate);
1069484Sgarrett.damore@Sun.COM }
1079484Sgarrett.damore@Sun.COM 
10811936Sgdamore@opensolaris.org uint_t
auclnt_get_fragsz(audio_stream_t * sp)1099484Sgarrett.damore@Sun.COM auclnt_get_fragsz(audio_stream_t *sp)
1109484Sgarrett.damore@Sun.COM {
1119484Sgarrett.damore@Sun.COM 	return (sp->s_fragbytes);
1129484Sgarrett.damore@Sun.COM }
1139484Sgarrett.damore@Sun.COM 
11411936Sgdamore@opensolaris.org uint_t
auclnt_get_framesz(audio_stream_t * sp)1159484Sgarrett.damore@Sun.COM auclnt_get_framesz(audio_stream_t *sp)
1169484Sgarrett.damore@Sun.COM {
1179484Sgarrett.damore@Sun.COM 	return (sp->s_framesz);
1189484Sgarrett.damore@Sun.COM }
1199484Sgarrett.damore@Sun.COM 
12011936Sgdamore@opensolaris.org uint_t
auclnt_get_nfrags(audio_stream_t * sp)1219484Sgarrett.damore@Sun.COM auclnt_get_nfrags(audio_stream_t *sp)
1229484Sgarrett.damore@Sun.COM {
1239484Sgarrett.damore@Sun.COM 	return (sp->s_nfrags);
1249484Sgarrett.damore@Sun.COM }
1259484Sgarrett.damore@Sun.COM 
12611936Sgdamore@opensolaris.org uint_t
auclnt_get_nframes(audio_stream_t * sp)1279484Sgarrett.damore@Sun.COM auclnt_get_nframes(audio_stream_t *sp)
1289484Sgarrett.damore@Sun.COM {
1299484Sgarrett.damore@Sun.COM 	return (sp->s_nframes);
1309484Sgarrett.damore@Sun.COM }
1319484Sgarrett.damore@Sun.COM 
1329558Sgdamore@opensolaris.org void
auclnt_set_latency(audio_stream_t * sp,uint_t frags,uint_t bytes)13311936Sgdamore@opensolaris.org auclnt_set_latency(audio_stream_t *sp, uint_t frags, uint_t bytes)
1349558Sgdamore@opensolaris.org {
1359558Sgdamore@opensolaris.org 	mutex_enter(&sp->s_lock);
1369558Sgdamore@opensolaris.org 	sp->s_hintfrags = (uint16_t)frags;
1379558Sgdamore@opensolaris.org 	sp->s_hintsz = bytes;
1389558Sgdamore@opensolaris.org 	mutex_exit(&sp->s_lock);
1399558Sgdamore@opensolaris.org }
1409558Sgdamore@opensolaris.org 
1419484Sgarrett.damore@Sun.COM uint64_t
auclnt_get_head(audio_stream_t * sp)1429484Sgarrett.damore@Sun.COM auclnt_get_head(audio_stream_t *sp)
1439484Sgarrett.damore@Sun.COM {
1449484Sgarrett.damore@Sun.COM 	return (sp->s_head);
1459484Sgarrett.damore@Sun.COM }
1469484Sgarrett.damore@Sun.COM 
1479484Sgarrett.damore@Sun.COM uint64_t
auclnt_get_tail(audio_stream_t * sp)1489484Sgarrett.damore@Sun.COM auclnt_get_tail(audio_stream_t *sp)
1499484Sgarrett.damore@Sun.COM {
1509484Sgarrett.damore@Sun.COM 	return (sp->s_tail);
1519484Sgarrett.damore@Sun.COM }
1529484Sgarrett.damore@Sun.COM 
15311936Sgdamore@opensolaris.org uint_t
auclnt_get_hidx(audio_stream_t * sp)1549484Sgarrett.damore@Sun.COM auclnt_get_hidx(audio_stream_t *sp)
1559484Sgarrett.damore@Sun.COM {
1569484Sgarrett.damore@Sun.COM 	return (sp->s_hidx);
1579484Sgarrett.damore@Sun.COM }
1589484Sgarrett.damore@Sun.COM 
15911936Sgdamore@opensolaris.org uint_t
auclnt_get_tidx(audio_stream_t * sp)1609484Sgarrett.damore@Sun.COM auclnt_get_tidx(audio_stream_t *sp)
1619484Sgarrett.damore@Sun.COM {
1629484Sgarrett.damore@Sun.COM 	return (sp->s_tidx);
1639484Sgarrett.damore@Sun.COM }
1649484Sgarrett.damore@Sun.COM 
1659484Sgarrett.damore@Sun.COM audio_stream_t *
auclnt_input_stream(audio_client_t * c)1669484Sgarrett.damore@Sun.COM auclnt_input_stream(audio_client_t *c)
1679484Sgarrett.damore@Sun.COM {
1689484Sgarrett.damore@Sun.COM 	return (&c->c_istream);
1699484Sgarrett.damore@Sun.COM }
1709484Sgarrett.damore@Sun.COM 
1719484Sgarrett.damore@Sun.COM audio_stream_t *
auclnt_output_stream(audio_client_t * c)1729484Sgarrett.damore@Sun.COM auclnt_output_stream(audio_client_t *c)
1739484Sgarrett.damore@Sun.COM {
1749484Sgarrett.damore@Sun.COM 	return (&c->c_ostream);
1759484Sgarrett.damore@Sun.COM }
1769484Sgarrett.damore@Sun.COM 
17711936Sgdamore@opensolaris.org uint_t
auclnt_get_count(audio_stream_t * sp)1789484Sgarrett.damore@Sun.COM auclnt_get_count(audio_stream_t *sp)
1799484Sgarrett.damore@Sun.COM {
18011936Sgdamore@opensolaris.org 	uint_t	count;
1819484Sgarrett.damore@Sun.COM 
1829484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
1839484Sgarrett.damore@Sun.COM 	ASSERT((sp->s_head - sp->s_tail) <= sp->s_nframes);
18411936Sgdamore@opensolaris.org 	count = (uint_t)(sp->s_head - sp->s_tail);
1859484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
1869484Sgarrett.damore@Sun.COM 
1879484Sgarrett.damore@Sun.COM 	return (count);
1889484Sgarrett.damore@Sun.COM }
1899484Sgarrett.damore@Sun.COM 
19011936Sgdamore@opensolaris.org uint_t
auclnt_consume(audio_stream_t * sp,uint_t n)19111936Sgdamore@opensolaris.org auclnt_consume(audio_stream_t *sp, uint_t n)
1929484Sgarrett.damore@Sun.COM {
1939484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
1949484Sgarrett.damore@Sun.COM 
1959484Sgarrett.damore@Sun.COM 	ASSERT(sp == &sp->s_client->c_istream);
1969484Sgarrett.damore@Sun.COM 	n = max(n, sp->s_head - sp->s_tail);
1979484Sgarrett.damore@Sun.COM 	sp->s_tail += n;
1989484Sgarrett.damore@Sun.COM 	sp->s_tidx += n;
1999484Sgarrett.damore@Sun.COM 	if (sp->s_tidx >= sp->s_nframes) {
2009484Sgarrett.damore@Sun.COM 		sp->s_tidx -= sp->s_nframes;
2019484Sgarrett.damore@Sun.COM 	}
2029484Sgarrett.damore@Sun.COM 
2039484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tail <= sp->s_head);
2049484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_hidx < sp->s_nframes);
2059484Sgarrett.damore@Sun.COM 
2069484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
2079484Sgarrett.damore@Sun.COM 
2089484Sgarrett.damore@Sun.COM 	return (n);
2099484Sgarrett.damore@Sun.COM }
2109484Sgarrett.damore@Sun.COM 
21111936Sgdamore@opensolaris.org uint_t
auclnt_consume_data(audio_stream_t * sp,caddr_t dst,uint_t n)21211936Sgdamore@opensolaris.org auclnt_consume_data(audio_stream_t *sp, caddr_t dst, uint_t n)
2139484Sgarrett.damore@Sun.COM {
21411936Sgdamore@opensolaris.org 	uint_t nframes;
21511936Sgdamore@opensolaris.org 	uint_t framesz;
21611936Sgdamore@opensolaris.org 	uint_t cnt;
2179484Sgarrett.damore@Sun.COM 	caddr_t	data;
2189484Sgarrett.damore@Sun.COM 
2199484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
2209484Sgarrett.damore@Sun.COM 
2219484Sgarrett.damore@Sun.COM 	nframes = sp->s_nframes;
2229484Sgarrett.damore@Sun.COM 	framesz = sp->s_framesz;
2239484Sgarrett.damore@Sun.COM 
2249484Sgarrett.damore@Sun.COM 	ASSERT(sp == &sp->s_client->c_istream);
2259484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_head >= sp->s_tail);
2269484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tidx < nframes);
2279484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_hidx < nframes);
2289484Sgarrett.damore@Sun.COM 
2299484Sgarrett.damore@Sun.COM 	cnt = n = min(n, sp->s_head - sp->s_tail);
2309484Sgarrett.damore@Sun.COM 	data = sp->s_data + (sp->s_tidx * framesz);
2319484Sgarrett.damore@Sun.COM 	do {
23211936Sgdamore@opensolaris.org 		uint_t nf, nb;
2339484Sgarrett.damore@Sun.COM 
2349484Sgarrett.damore@Sun.COM 		nf = min(nframes - sp->s_tidx, n);
2359484Sgarrett.damore@Sun.COM 		nb = nf * framesz;
2369484Sgarrett.damore@Sun.COM 
2379484Sgarrett.damore@Sun.COM 		bcopy(data, dst, nb);
2389484Sgarrett.damore@Sun.COM 		dst += nb;
2399484Sgarrett.damore@Sun.COM 		data += nb;
2409484Sgarrett.damore@Sun.COM 
2419484Sgarrett.damore@Sun.COM 		n -= nf;
2429484Sgarrett.damore@Sun.COM 		sp->s_tail += nf;
2439484Sgarrett.damore@Sun.COM 		sp->s_tidx += nf;
2449484Sgarrett.damore@Sun.COM 		if (sp->s_tidx == nframes) {
2459484Sgarrett.damore@Sun.COM 			sp->s_tidx = 0;
2469484Sgarrett.damore@Sun.COM 			data = sp->s_data;
2479484Sgarrett.damore@Sun.COM 		}
2489484Sgarrett.damore@Sun.COM 	} while (n);
2499484Sgarrett.damore@Sun.COM 
2509484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tail <= sp->s_head);
2519484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tidx < nframes);
2529484Sgarrett.damore@Sun.COM 
2539484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
2549484Sgarrett.damore@Sun.COM 
2559484Sgarrett.damore@Sun.COM 	return (cnt);
2569484Sgarrett.damore@Sun.COM }
2579484Sgarrett.damore@Sun.COM 
25811936Sgdamore@opensolaris.org uint_t
auclnt_produce(audio_stream_t * sp,uint_t n)25911936Sgdamore@opensolaris.org auclnt_produce(audio_stream_t *sp, uint_t n)
2609484Sgarrett.damore@Sun.COM {
2619484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
2629484Sgarrett.damore@Sun.COM 
2639484Sgarrett.damore@Sun.COM 	ASSERT(sp == &sp->s_client->c_ostream);
2649484Sgarrett.damore@Sun.COM 	n = max(n, sp->s_nframes - (sp->s_head - sp->s_tail));
2659484Sgarrett.damore@Sun.COM 	sp->s_head += n;
2669484Sgarrett.damore@Sun.COM 	sp->s_hidx += n;
2679484Sgarrett.damore@Sun.COM 	if (sp->s_hidx >= sp->s_nframes) {
2689484Sgarrett.damore@Sun.COM 		sp->s_hidx -= sp->s_nframes;
2699484Sgarrett.damore@Sun.COM 	}
2709484Sgarrett.damore@Sun.COM 
2719484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tail <= sp->s_head);
2729484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_hidx < sp->s_nframes);
2739484Sgarrett.damore@Sun.COM 
2749484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
2759484Sgarrett.damore@Sun.COM 
2769484Sgarrett.damore@Sun.COM 	return (n);
2779484Sgarrett.damore@Sun.COM }
2789484Sgarrett.damore@Sun.COM 
27911936Sgdamore@opensolaris.org uint_t
auclnt_produce_data(audio_stream_t * sp,caddr_t src,uint_t n)28011936Sgdamore@opensolaris.org auclnt_produce_data(audio_stream_t *sp, caddr_t src, uint_t n)
2819484Sgarrett.damore@Sun.COM {
28211936Sgdamore@opensolaris.org 	uint_t nframes;
28311936Sgdamore@opensolaris.org 	uint_t framesz;
28411936Sgdamore@opensolaris.org 	uint_t cnt;
2859484Sgarrett.damore@Sun.COM 	caddr_t data;
2869484Sgarrett.damore@Sun.COM 
2879484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
2889484Sgarrett.damore@Sun.COM 
2899484Sgarrett.damore@Sun.COM 	nframes = sp->s_nframes;
2909484Sgarrett.damore@Sun.COM 	framesz = sp->s_framesz;
2919484Sgarrett.damore@Sun.COM 
2929484Sgarrett.damore@Sun.COM 	ASSERT(sp == &sp->s_client->c_ostream);
2939484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_head >= sp->s_tail);
2949484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tidx < nframes);
2959484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_hidx < nframes);
2969484Sgarrett.damore@Sun.COM 
2979484Sgarrett.damore@Sun.COM 	cnt = n = min(n, nframes - (sp->s_head - sp->s_tail));
2989484Sgarrett.damore@Sun.COM 	data = sp->s_data + (sp->s_hidx * framesz);
2999484Sgarrett.damore@Sun.COM 	do {
30011936Sgdamore@opensolaris.org 		uint_t nf, nb;
3019484Sgarrett.damore@Sun.COM 
3029484Sgarrett.damore@Sun.COM 		nf = min(nframes - sp->s_hidx, n);
3039484Sgarrett.damore@Sun.COM 		nb = nf * framesz;
3049484Sgarrett.damore@Sun.COM 
3059484Sgarrett.damore@Sun.COM 		bcopy(src, data, nb);
3069484Sgarrett.damore@Sun.COM 
3079484Sgarrett.damore@Sun.COM 		src += nb;
3089484Sgarrett.damore@Sun.COM 		data += nb;
3099484Sgarrett.damore@Sun.COM 
3109484Sgarrett.damore@Sun.COM 		n -= nf;
3119484Sgarrett.damore@Sun.COM 		sp->s_head += nf;
3129484Sgarrett.damore@Sun.COM 		sp->s_hidx += nf;
3139484Sgarrett.damore@Sun.COM 		if (sp->s_hidx == nframes) {
3149484Sgarrett.damore@Sun.COM 			sp->s_hidx = 0;
3159484Sgarrett.damore@Sun.COM 			data = sp->s_data;
3169484Sgarrett.damore@Sun.COM 		}
3179484Sgarrett.damore@Sun.COM 	} while (n);
3189484Sgarrett.damore@Sun.COM 
3199484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tail <= sp->s_head);
3209484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_hidx < nframes);
3219484Sgarrett.damore@Sun.COM 
3229484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
3239484Sgarrett.damore@Sun.COM 
3249484Sgarrett.damore@Sun.COM 	return (cnt);
3259484Sgarrett.damore@Sun.COM }
3269484Sgarrett.damore@Sun.COM 
3279484Sgarrett.damore@Sun.COM int
auclnt_read(audio_client_t * c,struct uio * uio)3289484Sgarrett.damore@Sun.COM auclnt_read(audio_client_t *c, struct uio *uio)
3299484Sgarrett.damore@Sun.COM {
3309484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp = &c->c_istream;
33111936Sgdamore@opensolaris.org 	uint_t		cnt;
3329484Sgarrett.damore@Sun.COM 	int		rv = 0;
3339484Sgarrett.damore@Sun.COM 	offset_t	loff;
3349484Sgarrett.damore@Sun.COM 	int		eagain;
33511936Sgdamore@opensolaris.org 	uint_t		tidx;
33611936Sgdamore@opensolaris.org 	uint_t		framesz;
3379484Sgarrett.damore@Sun.COM 
3389484Sgarrett.damore@Sun.COM 	loff = uio->uio_loffset;
3399484Sgarrett.damore@Sun.COM 	eagain = EAGAIN;
3409484Sgarrett.damore@Sun.COM 
3419484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
3429484Sgarrett.damore@Sun.COM 
3439484Sgarrett.damore@Sun.COM 	if ((!sp->s_paused) && (!sp->s_running)) {
3449484Sgarrett.damore@Sun.COM 		mutex_exit(&sp->s_lock);
3459484Sgarrett.damore@Sun.COM 		auclnt_start(sp);
3469484Sgarrett.damore@Sun.COM 		mutex_enter(&sp->s_lock);
3479484Sgarrett.damore@Sun.COM 	}
3489484Sgarrett.damore@Sun.COM 
34911936Sgdamore@opensolaris.org 
35011936Sgdamore@opensolaris.org 	framesz = sp->s_framesz;
35111936Sgdamore@opensolaris.org 
3529484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_head >= sp->s_tail);
3539484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tidx < sp->s_nframes);
3549484Sgarrett.damore@Sun.COM 
35511936Sgdamore@opensolaris.org 	while (uio->uio_resid >= framesz) {
3569484Sgarrett.damore@Sun.COM 
3579484Sgarrett.damore@Sun.COM 		while ((cnt = (sp->s_head - sp->s_tail)) == 0) {
3589484Sgarrett.damore@Sun.COM 			if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
3599484Sgarrett.damore@Sun.COM 				mutex_exit(&sp->s_lock);
3609484Sgarrett.damore@Sun.COM 				return (eagain);
3619484Sgarrett.damore@Sun.COM 			}
3629484Sgarrett.damore@Sun.COM 			if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
3639484Sgarrett.damore@Sun.COM 				mutex_exit(&sp->s_lock);
3649484Sgarrett.damore@Sun.COM 				return (EINTR);
3659484Sgarrett.damore@Sun.COM 			}
3669484Sgarrett.damore@Sun.COM 		}
3679484Sgarrett.damore@Sun.COM 
36811936Sgdamore@opensolaris.org 		tidx = sp->s_tidx;
36911936Sgdamore@opensolaris.org 		cnt = min(cnt, sp->s_nframes - tidx);
37011936Sgdamore@opensolaris.org 		cnt = min(cnt, (uio->uio_resid / framesz));
3719484Sgarrett.damore@Sun.COM 
37211936Sgdamore@opensolaris.org 		mutex_exit(&sp->s_lock);
37311936Sgdamore@opensolaris.org 		rv = uiomove(sp->s_data + (tidx * framesz),
37411936Sgdamore@opensolaris.org 		    cnt * framesz, UIO_READ, uio);
37511936Sgdamore@opensolaris.org 
3769484Sgarrett.damore@Sun.COM 		uio->uio_loffset = loff;
3779484Sgarrett.damore@Sun.COM 		eagain = 0;
3789484Sgarrett.damore@Sun.COM 
3799484Sgarrett.damore@Sun.COM 		if (rv != 0) {
3809484Sgarrett.damore@Sun.COM 			return (rv);
3819484Sgarrett.damore@Sun.COM 		}
3829484Sgarrett.damore@Sun.COM 
38311936Sgdamore@opensolaris.org 		mutex_enter(&sp->s_lock);
3849484Sgarrett.damore@Sun.COM 		sp->s_tail += cnt;
3859484Sgarrett.damore@Sun.COM 		sp->s_tidx += cnt;
3869484Sgarrett.damore@Sun.COM 		if (sp->s_tidx == sp->s_nframes) {
3879484Sgarrett.damore@Sun.COM 			sp->s_tidx = 0;
3889484Sgarrett.damore@Sun.COM 		}
3899484Sgarrett.damore@Sun.COM 	}
3909484Sgarrett.damore@Sun.COM 
3919484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tail <= sp->s_head);
3929484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tidx < sp->s_nframes);
3939484Sgarrett.damore@Sun.COM 
3949484Sgarrett.damore@Sun.COM 	/* round off any remaining partial bits */
3959484Sgarrett.damore@Sun.COM 	uio->uio_resid = 0;
3969484Sgarrett.damore@Sun.COM 
3979484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
3989484Sgarrett.damore@Sun.COM 
3999484Sgarrett.damore@Sun.COM 	return (rv);
4009484Sgarrett.damore@Sun.COM }
4019484Sgarrett.damore@Sun.COM 
4029484Sgarrett.damore@Sun.COM int
auclnt_write(audio_client_t * c,struct uio * uio)4039484Sgarrett.damore@Sun.COM auclnt_write(audio_client_t *c, struct uio *uio)
4049484Sgarrett.damore@Sun.COM {
4059484Sgarrett.damore@Sun.COM 	audio_stream_t *sp = &c->c_ostream;
40611936Sgdamore@opensolaris.org 	uint_t		cnt;
4079484Sgarrett.damore@Sun.COM 	int		rv = 0;
4089484Sgarrett.damore@Sun.COM 	offset_t	loff;
4099484Sgarrett.damore@Sun.COM 	int		eagain;
41011936Sgdamore@opensolaris.org 	uint_t		framesz;
41111936Sgdamore@opensolaris.org 	uint_t		hidx;
4129484Sgarrett.damore@Sun.COM 
4139484Sgarrett.damore@Sun.COM 	loff = uio->uio_loffset;
4149484Sgarrett.damore@Sun.COM 	eagain = EAGAIN;
4159484Sgarrett.damore@Sun.COM 
4169484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
4179484Sgarrett.damore@Sun.COM 
41811936Sgdamore@opensolaris.org 	framesz = sp->s_framesz;
41911936Sgdamore@opensolaris.org 
4209484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_head >= sp->s_tail);
4219484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_hidx < sp->s_nframes);
4229484Sgarrett.damore@Sun.COM 
42311936Sgdamore@opensolaris.org 	while (uio->uio_resid >= framesz) {
4249484Sgarrett.damore@Sun.COM 
4259484Sgarrett.damore@Sun.COM 		while ((cnt = sp->s_nframes - (sp->s_head - sp->s_tail)) == 0) {
4269484Sgarrett.damore@Sun.COM 			if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
4279484Sgarrett.damore@Sun.COM 				mutex_exit(&sp->s_lock);
4289484Sgarrett.damore@Sun.COM 				return (eagain);
4299484Sgarrett.damore@Sun.COM 			}
4309484Sgarrett.damore@Sun.COM 			if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
4319484Sgarrett.damore@Sun.COM 				mutex_exit(&sp->s_lock);
4329484Sgarrett.damore@Sun.COM 				return (EINTR);
4339484Sgarrett.damore@Sun.COM 			}
4349484Sgarrett.damore@Sun.COM 		}
4359484Sgarrett.damore@Sun.COM 
43611936Sgdamore@opensolaris.org 		hidx = sp->s_hidx;
43711936Sgdamore@opensolaris.org 		cnt = min(cnt, sp->s_nframes - hidx);
43811936Sgdamore@opensolaris.org 		cnt = min(cnt, (uio->uio_resid / framesz));
4399484Sgarrett.damore@Sun.COM 
44011936Sgdamore@opensolaris.org 		/*
44111936Sgdamore@opensolaris.org 		 * We have to drop the stream lock, because the
44211936Sgdamore@opensolaris.org 		 * uiomove might require doing a page in, which could
44311936Sgdamore@opensolaris.org 		 * get blocked behind the PIL of the audio processing
44411936Sgdamore@opensolaris.org 		 * thread which also grabs the s_lock.  (Hence, there
44511936Sgdamore@opensolaris.org 		 * is a risk of deadlock due to priority inversion.)
44611936Sgdamore@opensolaris.org 		 */
44711936Sgdamore@opensolaris.org 		mutex_exit(&sp->s_lock);
44811936Sgdamore@opensolaris.org 
44911936Sgdamore@opensolaris.org 		rv = uiomove(sp->s_data + (hidx * framesz),
45011936Sgdamore@opensolaris.org 		    cnt * framesz, UIO_WRITE, uio);
45111936Sgdamore@opensolaris.org 
4529484Sgarrett.damore@Sun.COM 		uio->uio_loffset = loff;
4539484Sgarrett.damore@Sun.COM 		eagain = 0;
4549484Sgarrett.damore@Sun.COM 
4559484Sgarrett.damore@Sun.COM 		if (rv != 0) {
4569484Sgarrett.damore@Sun.COM 			return (rv);
4579484Sgarrett.damore@Sun.COM 		}
4589484Sgarrett.damore@Sun.COM 
45911936Sgdamore@opensolaris.org 		mutex_enter(&sp->s_lock);
46011936Sgdamore@opensolaris.org 
4619484Sgarrett.damore@Sun.COM 		sp->s_head += cnt;
4629484Sgarrett.damore@Sun.COM 		sp->s_hidx += cnt;
4639484Sgarrett.damore@Sun.COM 		if (sp->s_hidx == sp->s_nframes) {
4649484Sgarrett.damore@Sun.COM 			sp->s_hidx = 0;
4659484Sgarrett.damore@Sun.COM 		}
4669484Sgarrett.damore@Sun.COM 
4679484Sgarrett.damore@Sun.COM 		if ((!sp->s_paused) && (!sp->s_running) &&
4689484Sgarrett.damore@Sun.COM 		    ((sp->s_head - sp->s_tail) > sp->s_fragfr)) {
4699484Sgarrett.damore@Sun.COM 			mutex_exit(&sp->s_lock);
4709484Sgarrett.damore@Sun.COM 			auclnt_start(sp);
4719484Sgarrett.damore@Sun.COM 			mutex_enter(&sp->s_lock);
4729484Sgarrett.damore@Sun.COM 		}
4739484Sgarrett.damore@Sun.COM 	}
4749484Sgarrett.damore@Sun.COM 
4759484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_tail <= sp->s_head);
4769484Sgarrett.damore@Sun.COM 	ASSERT(sp->s_hidx < sp->s_nframes);
4779484Sgarrett.damore@Sun.COM 
4789484Sgarrett.damore@Sun.COM 	/* round off any remaining partial bits */
4799484Sgarrett.damore@Sun.COM 	uio->uio_resid = 0;
4809484Sgarrett.damore@Sun.COM 
4819484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
4829484Sgarrett.damore@Sun.COM 
4839484Sgarrett.damore@Sun.COM 	return (rv);
4849484Sgarrett.damore@Sun.COM }
4859484Sgarrett.damore@Sun.COM 
4869484Sgarrett.damore@Sun.COM int
auclnt_chpoll(audio_client_t * c,short events,int anyyet,short * reventsp,struct pollhead ** phpp)4879484Sgarrett.damore@Sun.COM auclnt_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp,
4889484Sgarrett.damore@Sun.COM     struct pollhead **phpp)
4899484Sgarrett.damore@Sun.COM {
4909484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp;
4919484Sgarrett.damore@Sun.COM 	short nev = 0;
4929484Sgarrett.damore@Sun.COM 
4939484Sgarrett.damore@Sun.COM 	if (events & (POLLIN | POLLRDNORM)) {
4949484Sgarrett.damore@Sun.COM 		sp = &c->c_istream;
4959484Sgarrett.damore@Sun.COM 		mutex_enter(&sp->s_lock);
4969484Sgarrett.damore@Sun.COM 		if ((sp->s_head - sp->s_tail) > sp->s_fragfr) {
4979484Sgarrett.damore@Sun.COM 			nev = POLLIN | POLLRDNORM;
4989484Sgarrett.damore@Sun.COM 		}
4999484Sgarrett.damore@Sun.COM 		mutex_exit(&sp->s_lock);
5009484Sgarrett.damore@Sun.COM 	}
5019484Sgarrett.damore@Sun.COM 
5029484Sgarrett.damore@Sun.COM 	if (events & POLLOUT) {
5039484Sgarrett.damore@Sun.COM 		sp = &c->c_ostream;
5049484Sgarrett.damore@Sun.COM 		mutex_enter(&sp->s_lock);
5059484Sgarrett.damore@Sun.COM 		if ((sp->s_nframes - (sp->s_head - sp->s_tail)) >
5069484Sgarrett.damore@Sun.COM 		    sp->s_fragfr) {
5079484Sgarrett.damore@Sun.COM 			nev = POLLOUT;
5089484Sgarrett.damore@Sun.COM 		}
5099484Sgarrett.damore@Sun.COM 		mutex_exit(&sp->s_lock);
5109484Sgarrett.damore@Sun.COM 	}
5119484Sgarrett.damore@Sun.COM 
5129484Sgarrett.damore@Sun.COM 	if (nev) {
5139484Sgarrett.damore@Sun.COM 		*reventsp = nev & events;
5149484Sgarrett.damore@Sun.COM 	} else {
5159484Sgarrett.damore@Sun.COM 		*reventsp = 0;
5169484Sgarrett.damore@Sun.COM 		if (!anyyet) {
5179484Sgarrett.damore@Sun.COM 			*phpp = &c->c_pollhead;
5189484Sgarrett.damore@Sun.COM 		}
5199484Sgarrett.damore@Sun.COM 	}
5209484Sgarrett.damore@Sun.COM 	return (0);
5219484Sgarrett.damore@Sun.COM }
5229484Sgarrett.damore@Sun.COM 
5239484Sgarrett.damore@Sun.COM void
auclnt_pollwakeup(audio_client_t * c,short events)5249484Sgarrett.damore@Sun.COM auclnt_pollwakeup(audio_client_t *c, short events)
5259484Sgarrett.damore@Sun.COM {
5269484Sgarrett.damore@Sun.COM 	pollwakeup(&c->c_pollhead, events);
5279484Sgarrett.damore@Sun.COM }
5289484Sgarrett.damore@Sun.COM 
5299484Sgarrett.damore@Sun.COM void
auclnt_get_output_qlen(audio_client_t * c,uint_t * slen,uint_t * flen)53011936Sgdamore@opensolaris.org auclnt_get_output_qlen(audio_client_t *c, uint_t *slen, uint_t *flen)
5319484Sgarrett.damore@Sun.COM {
5329484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp = &c->c_ostream;
5339484Sgarrett.damore@Sun.COM 	audio_engine_t	*e = sp->s_engine;
5349484Sgarrett.damore@Sun.COM 	uint64_t	el, sl;
53511936Sgdamore@opensolaris.org 	uint_t		cnt, er, sr;
5369484Sgarrett.damore@Sun.COM 
5379484Sgarrett.damore@Sun.COM 	if (e == NULL) {
5389484Sgarrett.damore@Sun.COM 		/* if no output engine, can't do it! */
5399484Sgarrett.damore@Sun.COM 		*slen = 0;
5409484Sgarrett.damore@Sun.COM 		*flen = 0;
5419484Sgarrett.damore@Sun.COM 		return;
5429484Sgarrett.damore@Sun.COM 	}
5439484Sgarrett.damore@Sun.COM 
5449484Sgarrett.damore@Sun.COM 	mutex_enter(&e->e_lock);
5459484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
54611213Sgdamore@opensolaris.org 	if (e->e_ops.audio_engine_qlen != NULL) {
54711213Sgdamore@opensolaris.org 		el = ENG_QLEN(e) + (e->e_head - e->e_tail);
54811213Sgdamore@opensolaris.org 	} else {
54911213Sgdamore@opensolaris.org 		el = (e->e_head - e->e_tail);
55011213Sgdamore@opensolaris.org 	}
5519484Sgarrett.damore@Sun.COM 	er = e->e_rate;
5529484Sgarrett.damore@Sun.COM 	sl = sp->s_cnv_cnt;
5539484Sgarrett.damore@Sun.COM 	sr = sp->s_user_parms->p_rate;
55411936Sgdamore@opensolaris.org 	cnt = (uint_t)(sp->s_head - sp->s_tail);
5559484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
5569484Sgarrett.damore@Sun.COM 	mutex_exit(&e->e_lock);
5579484Sgarrett.damore@Sun.COM 
5589484Sgarrett.damore@Sun.COM 	/* engine frames converted to stream rate, plus stream frames */
5599484Sgarrett.damore@Sun.COM 	*slen = cnt;
56011936Sgdamore@opensolaris.org 	*flen = ((uint_t)(((el * sr) / er) + sl));
5619484Sgarrett.damore@Sun.COM }
5629484Sgarrett.damore@Sun.COM 
5639484Sgarrett.damore@Sun.COM int
auclnt_set_format(audio_stream_t * sp,int fmt)5649484Sgarrett.damore@Sun.COM auclnt_set_format(audio_stream_t *sp, int fmt)
5659484Sgarrett.damore@Sun.COM {
5669484Sgarrett.damore@Sun.COM 	audio_parms_t	parms;
5679484Sgarrett.damore@Sun.COM 	int		rv = 0;
5689484Sgarrett.damore@Sun.COM 
5699484Sgarrett.damore@Sun.COM 	/*
5709484Sgarrett.damore@Sun.COM 	 * AC3: If we select an AC3 format, then we have to allocate
5719484Sgarrett.damore@Sun.COM 	 * another engine.  Normally this will be an output only
5729484Sgarrett.damore@Sun.COM 	 * engine.  However, for now we aren't supporting AC3
5739484Sgarrett.damore@Sun.COM 	 * passthru.
5749484Sgarrett.damore@Sun.COM 	 */
5759484Sgarrett.damore@Sun.COM 
5769484Sgarrett.damore@Sun.COM 	switch (fmt) {
5779484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_U8:
5789484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_ULAW:
5799484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_ALAW:
5809484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_S8:
5819484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_S16_LE:
5829484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_S16_BE:
5839484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_U16_LE:
5849484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_U16_BE:
5859484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_S24_LE:
5869484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_S24_BE:
5879484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_S32_LE:
5889484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_S32_BE:
5899484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_S24_PACKED:
5909484Sgarrett.damore@Sun.COM 		break;
5919484Sgarrett.damore@Sun.COM 
5929484Sgarrett.damore@Sun.COM 	case AUDIO_FORMAT_AC3:		/* AC3: PASSTHRU */
5939484Sgarrett.damore@Sun.COM 	default:
5949484Sgarrett.damore@Sun.COM 		return (ENOTSUP);
5959484Sgarrett.damore@Sun.COM 	}
5969484Sgarrett.damore@Sun.COM 
5979484Sgarrett.damore@Sun.COM 
5989484Sgarrett.damore@Sun.COM 	/*
5999484Sgarrett.damore@Sun.COM 	 * Optimization.  Some personalities send us the same format
6009484Sgarrett.damore@Sun.COM 	 * over and over again.  (Sun personality does this
6019484Sgarrett.damore@Sun.COM 	 * repeatedly.)  setup_src is potentially expensive, so we
6029484Sgarrett.damore@Sun.COM 	 * avoid doing it unless we really need to.
6039484Sgarrett.damore@Sun.COM 	 */
60412165Sgdamore@opensolaris.org 	if (fmt != sp->s_user_parms->p_format) {
6059484Sgarrett.damore@Sun.COM 		/*
6069484Sgarrett.damore@Sun.COM 		 * Note that setting the format doesn't check that the
6079484Sgarrett.damore@Sun.COM 		 * audio streams have been paused.  As a result, any
6089484Sgarrett.damore@Sun.COM 		 * data still playing or recording will probably get
6099484Sgarrett.damore@Sun.COM 		 * misinterpreted.  It would be smart if the client
6109484Sgarrett.damore@Sun.COM 		 * application paused/stopped playback before changing
6119484Sgarrett.damore@Sun.COM 		 * formats.
6129484Sgarrett.damore@Sun.COM 		 */
6139484Sgarrett.damore@Sun.COM 		parms.p_format = fmt;
61412165Sgdamore@opensolaris.org 		rv = auimpl_engine_setup(sp, 0, &parms, FORMAT_MSK_FMT);
6159484Sgarrett.damore@Sun.COM 	}
6169484Sgarrett.damore@Sun.COM 
6179484Sgarrett.damore@Sun.COM 	return (rv);
6189484Sgarrett.damore@Sun.COM }
6199484Sgarrett.damore@Sun.COM 
6209484Sgarrett.damore@Sun.COM int
auclnt_get_format(audio_stream_t * sp)6219484Sgarrett.damore@Sun.COM auclnt_get_format(audio_stream_t *sp)
6229484Sgarrett.damore@Sun.COM {
6239484Sgarrett.damore@Sun.COM 	return (sp->s_user_parms->p_format);
6249484Sgarrett.damore@Sun.COM }
6259484Sgarrett.damore@Sun.COM 
6269484Sgarrett.damore@Sun.COM int
auclnt_get_output_format(audio_client_t * c)6279484Sgarrett.damore@Sun.COM auclnt_get_output_format(audio_client_t *c)
6289484Sgarrett.damore@Sun.COM {
6299484Sgarrett.damore@Sun.COM 	return (c->c_ostream.s_user_parms->p_format);
6309484Sgarrett.damore@Sun.COM }
6319484Sgarrett.damore@Sun.COM 
6329484Sgarrett.damore@Sun.COM int
auclnt_get_input_format(audio_client_t * c)6339484Sgarrett.damore@Sun.COM auclnt_get_input_format(audio_client_t *c)
6349484Sgarrett.damore@Sun.COM {
6359484Sgarrett.damore@Sun.COM 	return (c->c_istream.s_user_parms->p_format);
6369484Sgarrett.damore@Sun.COM }
6379484Sgarrett.damore@Sun.COM 
6389484Sgarrett.damore@Sun.COM int
auclnt_set_channels(audio_stream_t * sp,int nchan)6399484Sgarrett.damore@Sun.COM auclnt_set_channels(audio_stream_t *sp, int nchan)
6409484Sgarrett.damore@Sun.COM {
6419484Sgarrett.damore@Sun.COM 	audio_parms_t	parms;
6429484Sgarrett.damore@Sun.COM 	int		rv = 0;
6439484Sgarrett.damore@Sun.COM 
6449484Sgarrett.damore@Sun.COM 	/* Validate setting */
6459484Sgarrett.damore@Sun.COM 	if ((nchan > AUDIO_MAX_CHANNELS) || (nchan < 1)) {
6469484Sgarrett.damore@Sun.COM 		return (EINVAL);
6479484Sgarrett.damore@Sun.COM 	}
6489484Sgarrett.damore@Sun.COM 
64912165Sgdamore@opensolaris.org 	if (nchan != sp->s_user_parms->p_nchan) {
6509484Sgarrett.damore@Sun.COM 		parms.p_nchan = nchan;
65112165Sgdamore@opensolaris.org 		rv = auimpl_engine_setup(sp, 0, &parms, FORMAT_MSK_CHAN);
6529484Sgarrett.damore@Sun.COM 	}
6539484Sgarrett.damore@Sun.COM 
6549484Sgarrett.damore@Sun.COM 	return (rv);
6559484Sgarrett.damore@Sun.COM }
6569484Sgarrett.damore@Sun.COM 
6579484Sgarrett.damore@Sun.COM int
auclnt_get_channels(audio_stream_t * sp)6589484Sgarrett.damore@Sun.COM auclnt_get_channels(audio_stream_t *sp)
6599484Sgarrett.damore@Sun.COM {
6609484Sgarrett.damore@Sun.COM 	return (sp->s_user_parms->p_nchan);
6619484Sgarrett.damore@Sun.COM }
6629484Sgarrett.damore@Sun.COM 
66310570Sgdamore@opensolaris.org 
66410570Sgdamore@opensolaris.org static void
auimpl_set_gain_master(audio_stream_t * sp,uint8_t gain)6659484Sgarrett.damore@Sun.COM auimpl_set_gain_master(audio_stream_t *sp, uint8_t gain)
6669484Sgarrett.damore@Sun.COM {
6679484Sgarrett.damore@Sun.COM 	uint32_t	scaled;
6689484Sgarrett.damore@Sun.COM 
6699484Sgarrett.damore@Sun.COM 	if (gain > 100) {
6709484Sgarrett.damore@Sun.COM 		gain = 0;
6719484Sgarrett.damore@Sun.COM 	}
6729484Sgarrett.damore@Sun.COM 
6739484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
6749484Sgarrett.damore@Sun.COM 	if (sp->s_gain_master == gain) {
6759484Sgarrett.damore@Sun.COM 		mutex_exit(&sp->s_lock);
6769484Sgarrett.damore@Sun.COM 		return;
6779484Sgarrett.damore@Sun.COM 	}
6789484Sgarrett.damore@Sun.COM 
6799484Sgarrett.damore@Sun.COM 	/*
6809484Sgarrett.damore@Sun.COM 	 * calculate the scaled values.  Done now to avoid calculations
6819484Sgarrett.damore@Sun.COM 	 * later.
6829484Sgarrett.damore@Sun.COM 	 */
6839484Sgarrett.damore@Sun.COM 	scaled = (gain * sp->s_gain_pct * AUDIO_DB_SIZE) / (100 * 100);
6849484Sgarrett.damore@Sun.COM 
6859484Sgarrett.damore@Sun.COM 	sp->s_gain_master = gain;
6869484Sgarrett.damore@Sun.COM 	sp->s_gain_scaled = auimpl_db_table[scaled];
6879484Sgarrett.damore@Sun.COM 
6889484Sgarrett.damore@Sun.COM 	if (!sp->s_muted) {
6899484Sgarrett.damore@Sun.COM 		sp->s_gain_eff = sp->s_gain_scaled;
6909484Sgarrett.damore@Sun.COM 	}
6919484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
6929484Sgarrett.damore@Sun.COM }
6939484Sgarrett.damore@Sun.COM 
69410570Sgdamore@opensolaris.org int
auimpl_set_pcmvol(void * arg,uint64_t val)69510570Sgdamore@opensolaris.org auimpl_set_pcmvol(void *arg, uint64_t val)
69610570Sgdamore@opensolaris.org {
69710570Sgdamore@opensolaris.org 	audio_dev_t	*d = arg;
69810570Sgdamore@opensolaris.org 	list_t		*l = &d->d_clients;
69910570Sgdamore@opensolaris.org 	audio_client_t	*c;
70010570Sgdamore@opensolaris.org 
70110570Sgdamore@opensolaris.org 	if (val > 100) {
70210570Sgdamore@opensolaris.org 		return (EINVAL);
70310570Sgdamore@opensolaris.org 	}
70410570Sgdamore@opensolaris.org 	rw_enter(&auimpl_client_lock, RW_WRITER);
70510570Sgdamore@opensolaris.org 	d->d_pcmvol = val & 0xff;
70610570Sgdamore@opensolaris.org 	rw_downgrade(&auimpl_client_lock);
70710570Sgdamore@opensolaris.org 
70810570Sgdamore@opensolaris.org 	for (c = list_head(l); c; c = list_next(l, c)) {
70910570Sgdamore@opensolaris.org 		/* don't need to check is_active here, its safe */
71010570Sgdamore@opensolaris.org 		auimpl_set_gain_master(&c->c_ostream, (uint8_t)val);
71110570Sgdamore@opensolaris.org 	}
71210570Sgdamore@opensolaris.org 	rw_exit(&auimpl_client_lock);
71310570Sgdamore@opensolaris.org 
71410570Sgdamore@opensolaris.org 	return (0);
71510570Sgdamore@opensolaris.org }
71610570Sgdamore@opensolaris.org 
71710570Sgdamore@opensolaris.org int
auimpl_get_pcmvol(void * arg,uint64_t * val)71810570Sgdamore@opensolaris.org auimpl_get_pcmvol(void *arg, uint64_t *val)
71910570Sgdamore@opensolaris.org {
72010570Sgdamore@opensolaris.org 	audio_dev_t	*d = arg;
72110570Sgdamore@opensolaris.org 
72210570Sgdamore@opensolaris.org 	*val = d->d_pcmvol;
72310570Sgdamore@opensolaris.org 	return (0);
72410570Sgdamore@opensolaris.org }
72510570Sgdamore@opensolaris.org 
7269484Sgarrett.damore@Sun.COM void
auclnt_set_gain(audio_stream_t * sp,uint8_t gain)7279484Sgarrett.damore@Sun.COM auclnt_set_gain(audio_stream_t *sp, uint8_t gain)
7289484Sgarrett.damore@Sun.COM {
7299484Sgarrett.damore@Sun.COM 	uint32_t	scaled;
7309484Sgarrett.damore@Sun.COM 
7319484Sgarrett.damore@Sun.COM 	if (gain > 100) {
7329484Sgarrett.damore@Sun.COM 		gain = 0;
7339484Sgarrett.damore@Sun.COM 	}
7349484Sgarrett.damore@Sun.COM 
7359484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
7369484Sgarrett.damore@Sun.COM 
7379484Sgarrett.damore@Sun.COM 	/* if no change, don't bother doing updates */
7389484Sgarrett.damore@Sun.COM 	if (sp->s_gain_pct == gain) {
7399484Sgarrett.damore@Sun.COM 		mutex_exit(&sp->s_lock);
7409484Sgarrett.damore@Sun.COM 		return;
7419484Sgarrett.damore@Sun.COM 	}
7429484Sgarrett.damore@Sun.COM 
7439484Sgarrett.damore@Sun.COM 	/*
7449484Sgarrett.damore@Sun.COM 	 * calculate the scaled values.  Done now to avoid calculations
7459484Sgarrett.damore@Sun.COM 	 * later.
7469484Sgarrett.damore@Sun.COM 	 */
7479484Sgarrett.damore@Sun.COM 	scaled = (gain * sp->s_gain_master * AUDIO_DB_SIZE) / (100 * 100);
7489484Sgarrett.damore@Sun.COM 
7499484Sgarrett.damore@Sun.COM 	sp->s_gain_pct = gain;
7509484Sgarrett.damore@Sun.COM 	sp->s_gain_scaled = auimpl_db_table[scaled];
7519484Sgarrett.damore@Sun.COM 
7529484Sgarrett.damore@Sun.COM 	if (!sp->s_muted) {
7539484Sgarrett.damore@Sun.COM 		sp->s_gain_eff = sp->s_gain_scaled;
7549484Sgarrett.damore@Sun.COM 	}
7559484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
7569484Sgarrett.damore@Sun.COM 
75710632Sgdamore@opensolaris.org 	atomic_inc_uint(&sp->s_client->c_dev->d_serial);
7589484Sgarrett.damore@Sun.COM }
7599484Sgarrett.damore@Sun.COM 
7609484Sgarrett.damore@Sun.COM uint8_t
auclnt_get_gain(audio_stream_t * sp)7619484Sgarrett.damore@Sun.COM auclnt_get_gain(audio_stream_t *sp)
7629484Sgarrett.damore@Sun.COM {
7639484Sgarrett.damore@Sun.COM 	return (sp->s_gain_pct);
7649484Sgarrett.damore@Sun.COM }
7659484Sgarrett.damore@Sun.COM 
7669484Sgarrett.damore@Sun.COM void
auclnt_set_muted(audio_stream_t * sp,boolean_t muted)7679484Sgarrett.damore@Sun.COM auclnt_set_muted(audio_stream_t *sp, boolean_t muted)
7689484Sgarrett.damore@Sun.COM {
7699484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
7709484Sgarrett.damore@Sun.COM 
7719484Sgarrett.damore@Sun.COM 	/* if no work change, don't bother doing updates */
7729484Sgarrett.damore@Sun.COM 	if (sp->s_muted == muted) {
7739484Sgarrett.damore@Sun.COM 		mutex_exit(&sp->s_lock);
7749484Sgarrett.damore@Sun.COM 		return;
7759484Sgarrett.damore@Sun.COM 	}
7769484Sgarrett.damore@Sun.COM 
7779484Sgarrett.damore@Sun.COM 	sp->s_muted = muted;
7789484Sgarrett.damore@Sun.COM 	if (muted) {
7799484Sgarrett.damore@Sun.COM 		sp->s_gain_eff = 0;
7809484Sgarrett.damore@Sun.COM 	} else {
7819484Sgarrett.damore@Sun.COM 		sp->s_gain_eff = sp->s_gain_scaled;
7829484Sgarrett.damore@Sun.COM 	}
7839484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
7849484Sgarrett.damore@Sun.COM 
78510632Sgdamore@opensolaris.org 	atomic_inc_uint(&sp->s_client->c_dev->d_serial);
7869484Sgarrett.damore@Sun.COM }
7879484Sgarrett.damore@Sun.COM 
7889484Sgarrett.damore@Sun.COM boolean_t
auclnt_get_muted(audio_stream_t * sp)7899484Sgarrett.damore@Sun.COM auclnt_get_muted(audio_stream_t *sp)
7909484Sgarrett.damore@Sun.COM {
7919484Sgarrett.damore@Sun.COM 	return (sp->s_muted);
7929484Sgarrett.damore@Sun.COM }
7939484Sgarrett.damore@Sun.COM 
79410172Sgdamore@opensolaris.org boolean_t
auclnt_is_running(audio_stream_t * sp)79510172Sgdamore@opensolaris.org auclnt_is_running(audio_stream_t *sp)
79610172Sgdamore@opensolaris.org {
79710172Sgdamore@opensolaris.org 	return (sp->s_running);
79810172Sgdamore@opensolaris.org }
79910172Sgdamore@opensolaris.org 
8009484Sgarrett.damore@Sun.COM void
auclnt_start(audio_stream_t * sp)8019484Sgarrett.damore@Sun.COM auclnt_start(audio_stream_t *sp)
8029484Sgarrett.damore@Sun.COM {
8039484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
8049484Sgarrett.damore@Sun.COM 	sp->s_running = B_TRUE;
8059484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
8069484Sgarrett.damore@Sun.COM }
8079484Sgarrett.damore@Sun.COM 
8089484Sgarrett.damore@Sun.COM void
auclnt_stop(audio_stream_t * sp)8099484Sgarrett.damore@Sun.COM auclnt_stop(audio_stream_t *sp)
8109484Sgarrett.damore@Sun.COM {
8119484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
8129484Sgarrett.damore@Sun.COM 	/* if running, then stop it */
8139484Sgarrett.damore@Sun.COM 	if (sp->s_running) {
8149484Sgarrett.damore@Sun.COM 		sp->s_running = B_FALSE;
8159484Sgarrett.damore@Sun.COM 		/*
8169484Sgarrett.damore@Sun.COM 		 * if we stopped the engine, we might need to wake up
8179484Sgarrett.damore@Sun.COM 		 * a thread that is waiting for drain to complete.
8189484Sgarrett.damore@Sun.COM 		 */
8199484Sgarrett.damore@Sun.COM 		cv_broadcast(&sp->s_cv);
8209484Sgarrett.damore@Sun.COM 	}
8219484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
8229484Sgarrett.damore@Sun.COM }
8239484Sgarrett.damore@Sun.COM 
8249484Sgarrett.damore@Sun.COM /*
8259484Sgarrett.damore@Sun.COM  * When pausing, no new data will be played after the most recently
8269484Sgarrett.damore@Sun.COM  * mixed samples have played.  However, the audio engine will continue
8279484Sgarrett.damore@Sun.COM  * to play (possibly just silence).
8289484Sgarrett.damore@Sun.COM  *
8299484Sgarrett.damore@Sun.COM  * Note that we don't reference count the device, or release/close the
8309484Sgarrett.damore@Sun.COM  * engine here.  Once fired up, the engine continues running unil it
8319484Sgarrett.damore@Sun.COM  * is closed.
8329484Sgarrett.damore@Sun.COM  */
8339484Sgarrett.damore@Sun.COM void
auclnt_set_paused(audio_stream_t * sp)8349484Sgarrett.damore@Sun.COM auclnt_set_paused(audio_stream_t *sp)
8359484Sgarrett.damore@Sun.COM {
8369484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
8379484Sgarrett.damore@Sun.COM 	if (sp->s_paused) {
8389484Sgarrett.damore@Sun.COM 		mutex_exit(&sp->s_lock);
8399484Sgarrett.damore@Sun.COM 		return;
8409484Sgarrett.damore@Sun.COM 	}
8419484Sgarrett.damore@Sun.COM 	sp->s_paused = B_TRUE;
8429484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
8439484Sgarrett.damore@Sun.COM 
8449484Sgarrett.damore@Sun.COM 	auclnt_stop(sp);
8459484Sgarrett.damore@Sun.COM 
84610632Sgdamore@opensolaris.org 	atomic_inc_uint(&sp->s_client->c_dev->d_serial);
8479484Sgarrett.damore@Sun.COM }
8489484Sgarrett.damore@Sun.COM 
8499484Sgarrett.damore@Sun.COM void
auclnt_clear_paused(audio_stream_t * sp)8509484Sgarrett.damore@Sun.COM auclnt_clear_paused(audio_stream_t *sp)
8519484Sgarrett.damore@Sun.COM {
8529484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
8539484Sgarrett.damore@Sun.COM 	if (!sp->s_paused) {
8549484Sgarrett.damore@Sun.COM 		mutex_exit(&sp->s_lock);
8559484Sgarrett.damore@Sun.COM 		return;
8569484Sgarrett.damore@Sun.COM 	}
8579484Sgarrett.damore@Sun.COM 	sp->s_paused = B_FALSE;
8589484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
8599484Sgarrett.damore@Sun.COM }
8609484Sgarrett.damore@Sun.COM 
8619484Sgarrett.damore@Sun.COM boolean_t
auclnt_is_paused(audio_stream_t * sp)8629484Sgarrett.damore@Sun.COM auclnt_is_paused(audio_stream_t *sp)
8639484Sgarrett.damore@Sun.COM {
8649484Sgarrett.damore@Sun.COM 	return (sp->s_paused);
8659484Sgarrett.damore@Sun.COM }
8669484Sgarrett.damore@Sun.COM 
8679484Sgarrett.damore@Sun.COM void
auclnt_flush(audio_stream_t * sp)8689484Sgarrett.damore@Sun.COM auclnt_flush(audio_stream_t *sp)
8699484Sgarrett.damore@Sun.COM {
8709484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
8719484Sgarrett.damore@Sun.COM 	if (sp == &sp->s_client->c_ostream) {
8729484Sgarrett.damore@Sun.COM 		sp->s_tail = sp->s_head;
8739484Sgarrett.damore@Sun.COM 		sp->s_tidx = sp->s_hidx;
8749484Sgarrett.damore@Sun.COM 	} else {
8759484Sgarrett.damore@Sun.COM 		sp->s_head = sp->s_tail;
8769484Sgarrett.damore@Sun.COM 		sp->s_hidx = sp->s_tidx;
8779484Sgarrett.damore@Sun.COM 	}
8789484Sgarrett.damore@Sun.COM 	sp->s_cnv_cnt = 0;
8799484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
8809484Sgarrett.damore@Sun.COM }
8819484Sgarrett.damore@Sun.COM 
8829484Sgarrett.damore@Sun.COM int
auclnt_get_oflag(audio_client_t * c)8839484Sgarrett.damore@Sun.COM auclnt_get_oflag(audio_client_t *c)
8849484Sgarrett.damore@Sun.COM {
8859484Sgarrett.damore@Sun.COM 	return (c->c_omode);
8869484Sgarrett.damore@Sun.COM }
8879484Sgarrett.damore@Sun.COM 
8889484Sgarrett.damore@Sun.COM /*
8899484Sgarrett.damore@Sun.COM  * These routines should not be accessed by client "personality"
8909484Sgarrett.damore@Sun.COM  * implementations, but are for private framework use only.
8919484Sgarrett.damore@Sun.COM  */
8929484Sgarrett.damore@Sun.COM 
8939484Sgarrett.damore@Sun.COM void
auimpl_client_init(void)8949484Sgarrett.damore@Sun.COM auimpl_client_init(void)
8959484Sgarrett.damore@Sun.COM {
8969484Sgarrett.damore@Sun.COM 	rw_init(&auimpl_client_lock, NULL, RW_DRIVER, NULL);
8979484Sgarrett.damore@Sun.COM 	list_create(&auimpl_clients, sizeof (struct audio_client),
8989484Sgarrett.damore@Sun.COM 	    offsetof(struct audio_client, c_global_linkage));
8999484Sgarrett.damore@Sun.COM }
9009484Sgarrett.damore@Sun.COM 
9019484Sgarrett.damore@Sun.COM void
auimpl_client_fini(void)9029484Sgarrett.damore@Sun.COM auimpl_client_fini(void)
9039484Sgarrett.damore@Sun.COM {
9049484Sgarrett.damore@Sun.COM 	rw_destroy(&auimpl_client_lock);
9059484Sgarrett.damore@Sun.COM 	list_destroy(&auimpl_clients);
9069484Sgarrett.damore@Sun.COM }
9079484Sgarrett.damore@Sun.COM 
9089484Sgarrett.damore@Sun.COM static int
auimpl_stream_init(audio_stream_t * sp,audio_client_t * c)9099484Sgarrett.damore@Sun.COM auimpl_stream_init(audio_stream_t *sp, audio_client_t *c)
9109484Sgarrett.damore@Sun.COM {
9119484Sgarrett.damore@Sun.COM 	mutex_init(&sp->s_lock, NULL, MUTEX_DRIVER, NULL);
9129484Sgarrett.damore@Sun.COM 	cv_init(&sp->s_cv, NULL, CV_DRIVER, NULL);
9139484Sgarrett.damore@Sun.COM 	sp->s_client = c;
9149484Sgarrett.damore@Sun.COM 
9159484Sgarrett.damore@Sun.COM 	if (sp == &c->c_ostream) {
9169484Sgarrett.damore@Sun.COM 		sp->s_user_parms = &sp->s_cnv_src_parms;
9179484Sgarrett.damore@Sun.COM 		sp->s_phys_parms = &sp->s_cnv_dst_parms;
9189484Sgarrett.damore@Sun.COM 		sp->s_engcap = ENGINE_OUTPUT_CAP;
9199484Sgarrett.damore@Sun.COM 	} else {
9209484Sgarrett.damore@Sun.COM 		ASSERT(sp == &c->c_istream);
9219484Sgarrett.damore@Sun.COM 		sp->s_user_parms = &sp->s_cnv_dst_parms;
9229484Sgarrett.damore@Sun.COM 		sp->s_phys_parms = &sp->s_cnv_src_parms;
9239484Sgarrett.damore@Sun.COM 		sp->s_engcap = ENGINE_INPUT_CAP;
9249484Sgarrett.damore@Sun.COM 	}
9259484Sgarrett.damore@Sun.COM 
9269484Sgarrett.damore@Sun.COM 	/* for now initialize conversion parameters */
9279484Sgarrett.damore@Sun.COM 	sp->s_src_quality = 3;	/* reasonable compromise for now */
9289484Sgarrett.damore@Sun.COM 	sp->s_cnv_dst_nchan = 2;
9299484Sgarrett.damore@Sun.COM 	sp->s_cnv_dst_format = AUDIO_FORMAT_S24_NE;
9309484Sgarrett.damore@Sun.COM 	sp->s_cnv_dst_rate = 48000;
9319484Sgarrett.damore@Sun.COM 	sp->s_cnv_src_nchan = 2;
9329484Sgarrett.damore@Sun.COM 	sp->s_cnv_src_format = AUDIO_FORMAT_S24_NE;
9339484Sgarrett.damore@Sun.COM 	sp->s_cnv_src_rate = 48000;
9349484Sgarrett.damore@Sun.COM 
9359484Sgarrett.damore@Sun.COM 	/* set volume/gain all the way up */
9369484Sgarrett.damore@Sun.COM 	sp->s_muted = B_FALSE;
9379484Sgarrett.damore@Sun.COM 	sp->s_gain_pct = 0;
9389484Sgarrett.damore@Sun.COM 	sp->s_gain_scaled = AUDIO_VOL_SCALE;
9399484Sgarrett.damore@Sun.COM 	sp->s_gain_eff = AUDIO_VOL_SCALE;
9409484Sgarrett.damore@Sun.COM 
9419484Sgarrett.damore@Sun.COM 	/*
9429484Sgarrett.damore@Sun.COM 	 * We have to start off with a reasonable buffer and
9439484Sgarrett.damore@Sun.COM 	 * interrupt configuration.
9449484Sgarrett.damore@Sun.COM 	 */
9459484Sgarrett.damore@Sun.COM 	sp->s_allocsz = 65536;
9469484Sgarrett.damore@Sun.COM 	sp->s_data = ddi_umem_alloc(sp->s_allocsz, DDI_UMEM_NOSLEEP,
9479484Sgarrett.damore@Sun.COM 	    &sp->s_cookie);
9489484Sgarrett.damore@Sun.COM 	if (sp->s_data == NULL) {
9499484Sgarrett.damore@Sun.COM 		sp->s_allocsz = 0;
9509484Sgarrett.damore@Sun.COM 		audio_dev_warn(c->c_dev, "ddi_umem_alloc failed");
9519484Sgarrett.damore@Sun.COM 		return (ENOMEM);
9529484Sgarrett.damore@Sun.COM 	}
9539484Sgarrett.damore@Sun.COM 	/* make sure no stale data left in stream */
9549484Sgarrett.damore@Sun.COM 	bzero(sp->s_data, sp->s_allocsz);
9559484Sgarrett.damore@Sun.COM 
9569484Sgarrett.damore@Sun.COM 	/*
9579484Sgarrett.damore@Sun.COM 	 * Allocate SRC and data conversion state.
9589484Sgarrett.damore@Sun.COM 	 */
9599484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
9609484Sgarrett.damore@Sun.COM 	if (auimpl_format_alloc(sp) != 0) {
9619484Sgarrett.damore@Sun.COM 		mutex_exit(&sp->s_lock);
9629484Sgarrett.damore@Sun.COM 		return (ENOMEM);
9639484Sgarrett.damore@Sun.COM 	}
9649484Sgarrett.damore@Sun.COM 
9659484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
9669484Sgarrett.damore@Sun.COM 
9679484Sgarrett.damore@Sun.COM 	return (0);
9689484Sgarrett.damore@Sun.COM }
9699484Sgarrett.damore@Sun.COM 
9709484Sgarrett.damore@Sun.COM 
9719484Sgarrett.damore@Sun.COM static void
audio_stream_fini(audio_stream_t * sp)9729484Sgarrett.damore@Sun.COM audio_stream_fini(audio_stream_t *sp)
9739484Sgarrett.damore@Sun.COM {
9749484Sgarrett.damore@Sun.COM 	auimpl_format_free(sp);
9759484Sgarrett.damore@Sun.COM 	if (sp->s_cnv_buf0)
9769484Sgarrett.damore@Sun.COM 		kmem_free(sp->s_cnv_buf0, sp->s_cnv_max);
9779484Sgarrett.damore@Sun.COM 	if (sp->s_cnv_buf1)
9789484Sgarrett.damore@Sun.COM 		kmem_free(sp->s_cnv_buf1, sp->s_cnv_max);
9799484Sgarrett.damore@Sun.COM 	mutex_destroy(&sp->s_lock);
9809484Sgarrett.damore@Sun.COM 	cv_destroy(&sp->s_cv);
9819484Sgarrett.damore@Sun.COM 	if (sp->s_data != NULL) {
9829484Sgarrett.damore@Sun.COM 		ddi_umem_free(sp->s_cookie);
9839484Sgarrett.damore@Sun.COM 		sp->s_data = NULL;
9849484Sgarrett.damore@Sun.COM 	}
9859484Sgarrett.damore@Sun.COM }
9869484Sgarrett.damore@Sun.COM 
9879484Sgarrett.damore@Sun.COM int
auclnt_start_drain(audio_client_t * c)9889484Sgarrett.damore@Sun.COM auclnt_start_drain(audio_client_t *c)
9899484Sgarrett.damore@Sun.COM {
9909484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp;
9919484Sgarrett.damore@Sun.COM 	int		rv;
9929484Sgarrett.damore@Sun.COM 
9939484Sgarrett.damore@Sun.COM 	sp = &c->c_ostream;
9949484Sgarrett.damore@Sun.COM 
9959484Sgarrett.damore@Sun.COM 	/* start an asynchronous drain operation. */
9969484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
9979484Sgarrett.damore@Sun.COM 	if (sp->s_paused || !sp->s_running) {
9989484Sgarrett.damore@Sun.COM 		rv = EALREADY;
9999484Sgarrett.damore@Sun.COM 	} else {
10009484Sgarrett.damore@Sun.COM 		sp->s_draining = B_TRUE;
10019484Sgarrett.damore@Sun.COM 		rv = 0;
10029484Sgarrett.damore@Sun.COM 	}
10039484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
10049484Sgarrett.damore@Sun.COM 	return (rv);
10059484Sgarrett.damore@Sun.COM }
10069484Sgarrett.damore@Sun.COM 
10079484Sgarrett.damore@Sun.COM int
auclnt_drain(audio_client_t * c)10089484Sgarrett.damore@Sun.COM auclnt_drain(audio_client_t *c)
10099484Sgarrett.damore@Sun.COM {
10109484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp;
10119484Sgarrett.damore@Sun.COM 
10129484Sgarrett.damore@Sun.COM 	sp = &c->c_ostream;
10139484Sgarrett.damore@Sun.COM 
10149484Sgarrett.damore@Sun.COM 	/*
10159484Sgarrett.damore@Sun.COM 	 * Note: Drain logic will automatically "stop" the stream when
10169484Sgarrett.damore@Sun.COM 	 * the drain threshold has been reached.  So all we have to do
10179484Sgarrett.damore@Sun.COM 	 * is wait for the stream to stop.
10189484Sgarrett.damore@Sun.COM 	 */
10199484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
10209484Sgarrett.damore@Sun.COM 	sp->s_draining = B_TRUE;
10219484Sgarrett.damore@Sun.COM 	while (sp->s_draining && sp->s_running && !sp->s_paused) {
10229484Sgarrett.damore@Sun.COM 		if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
10239484Sgarrett.damore@Sun.COM 			mutex_exit(&sp->s_lock);
10249484Sgarrett.damore@Sun.COM 			return (EINTR);
10259484Sgarrett.damore@Sun.COM 		}
10269484Sgarrett.damore@Sun.COM 	}
10279484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
10289484Sgarrett.damore@Sun.COM 	return (0);
10299484Sgarrett.damore@Sun.COM }
10309484Sgarrett.damore@Sun.COM 
10319484Sgarrett.damore@Sun.COM audio_client_t *
auimpl_client_create(dev_t dev)10329484Sgarrett.damore@Sun.COM auimpl_client_create(dev_t dev)
10339484Sgarrett.damore@Sun.COM {
10349484Sgarrett.damore@Sun.COM 	audio_client_ops_t	*ops;
10359484Sgarrett.damore@Sun.COM 	audio_client_t		*c;
10369484Sgarrett.damore@Sun.COM 	audio_client_t		*next;
10379484Sgarrett.damore@Sun.COM 	list_t			*list = &auimpl_clients;
10389484Sgarrett.damore@Sun.COM 	minor_t			minor;
10399484Sgarrett.damore@Sun.COM 	audio_dev_t		*d;
10409484Sgarrett.damore@Sun.COM 
10419484Sgarrett.damore@Sun.COM 	/* validate minor number */
10429484Sgarrett.damore@Sun.COM 	minor = getminor(dev) & AUDIO_MN_TYPE_MASK;
10439484Sgarrett.damore@Sun.COM 	if ((ops = audio_client_ops[minor]) == NULL) {
10449484Sgarrett.damore@Sun.COM 		return (NULL);
10459484Sgarrett.damore@Sun.COM 	}
10469484Sgarrett.damore@Sun.COM 
10479484Sgarrett.damore@Sun.COM 	/* lookup device instance */
10489484Sgarrett.damore@Sun.COM 	if ((d = auimpl_dev_hold_by_devt(dev)) == NULL) {
10499484Sgarrett.damore@Sun.COM 		audio_dev_warn(NULL, "no audio_dev for dev_t %d,%d",
10509484Sgarrett.damore@Sun.COM 		    getmajor(dev), getminor(dev));
10519484Sgarrett.damore@Sun.COM 		return (NULL);
10529484Sgarrett.damore@Sun.COM 	}
10539484Sgarrett.damore@Sun.COM 
10549484Sgarrett.damore@Sun.COM 	if ((c = kmem_zalloc(sizeof (*c), KM_NOSLEEP)) == NULL) {
10559484Sgarrett.damore@Sun.COM 		audio_dev_warn(d, "unable to allocate client structure");
10569484Sgarrett.damore@Sun.COM 		auimpl_dev_release(d);
10579484Sgarrett.damore@Sun.COM 		return (NULL);
10589484Sgarrett.damore@Sun.COM 	}
10599484Sgarrett.damore@Sun.COM 	c->c_dev = d;
10609484Sgarrett.damore@Sun.COM 
10619484Sgarrett.damore@Sun.COM 	mutex_init(&c->c_lock, NULL, MUTEX_DRIVER, NULL);
10629484Sgarrett.damore@Sun.COM 	cv_init(&c->c_cv, NULL, CV_DRIVER, NULL);
10639484Sgarrett.damore@Sun.COM 
10649484Sgarrett.damore@Sun.COM 	if ((auimpl_stream_init(&c->c_ostream, c) != 0) ||
10659484Sgarrett.damore@Sun.COM 	    (auimpl_stream_init(&c->c_istream, c) != 0)) {
10669484Sgarrett.damore@Sun.COM 		goto failed;
10679484Sgarrett.damore@Sun.COM 	}
10689484Sgarrett.damore@Sun.COM 
10699484Sgarrett.damore@Sun.COM 	c->c_major =		getmajor(dev);
10709484Sgarrett.damore@Sun.COM 	c->c_origminor =	getminor(dev);
10719484Sgarrett.damore@Sun.COM 	c->c_ops =		*ops;
10729484Sgarrett.damore@Sun.COM 
10739484Sgarrett.damore@Sun.COM 	/*
10749484Sgarrett.damore@Sun.COM 	 * We hold the client lock here.
10759484Sgarrett.damore@Sun.COM 	 */
10769484Sgarrett.damore@Sun.COM 	rw_enter(&auimpl_client_lock, RW_WRITER);
10779484Sgarrett.damore@Sun.COM 
10789484Sgarrett.damore@Sun.COM 	minor = AUDIO_MN_CLONE_MASK;
10799484Sgarrett.damore@Sun.COM 	for (next = list_head(list); next; next = list_next(list, next)) {
10809484Sgarrett.damore@Sun.COM 		if (next->c_minor > minor) {
10819484Sgarrett.damore@Sun.COM 			break;
10829484Sgarrett.damore@Sun.COM 		}
10839484Sgarrett.damore@Sun.COM 		minor++;
10849484Sgarrett.damore@Sun.COM 	}
10859484Sgarrett.damore@Sun.COM 	if (minor >= MAXMIN32) {
10869484Sgarrett.damore@Sun.COM 		rw_exit(&auimpl_client_lock);
10879484Sgarrett.damore@Sun.COM 		goto failed;
10889484Sgarrett.damore@Sun.COM 	}
10899484Sgarrett.damore@Sun.COM 	c->c_minor = minor;
10909484Sgarrett.damore@Sun.COM 	list_insert_before(list, next, c);
10919484Sgarrett.damore@Sun.COM 
10929484Sgarrett.damore@Sun.COM 	rw_exit(&auimpl_client_lock);
10939484Sgarrett.damore@Sun.COM 
10949484Sgarrett.damore@Sun.COM 
10959484Sgarrett.damore@Sun.COM 	return (c);
10969484Sgarrett.damore@Sun.COM 
10979484Sgarrett.damore@Sun.COM failed:
10989484Sgarrett.damore@Sun.COM 	auimpl_dev_release(d);
10999484Sgarrett.damore@Sun.COM 	audio_stream_fini(&c->c_ostream);
11009484Sgarrett.damore@Sun.COM 	audio_stream_fini(&c->c_istream);
11019484Sgarrett.damore@Sun.COM 	mutex_destroy(&c->c_lock);
11029484Sgarrett.damore@Sun.COM 	cv_destroy(&c->c_cv);
11039484Sgarrett.damore@Sun.COM 	kmem_free(c, sizeof (*c));
11049484Sgarrett.damore@Sun.COM 	return (NULL);
11059484Sgarrett.damore@Sun.COM }
11069484Sgarrett.damore@Sun.COM 
11079484Sgarrett.damore@Sun.COM void
auimpl_client_destroy(audio_client_t * c)11089484Sgarrett.damore@Sun.COM auimpl_client_destroy(audio_client_t *c)
11099484Sgarrett.damore@Sun.COM {
11109484Sgarrett.damore@Sun.COM 	/* remove us from the global list */
11119484Sgarrett.damore@Sun.COM 	rw_enter(&auimpl_client_lock, RW_WRITER);
11129484Sgarrett.damore@Sun.COM 	list_remove(&auimpl_clients, c);
11139484Sgarrett.damore@Sun.COM 	rw_exit(&auimpl_client_lock);
11149484Sgarrett.damore@Sun.COM 
11159484Sgarrett.damore@Sun.COM 	ASSERT(!c->c_istream.s_running);
1116*12979SEdgar.Liu@Sun.COM 	ASSERT(!c->c_ostream.s_running);
11179484Sgarrett.damore@Sun.COM 
11189484Sgarrett.damore@Sun.COM 	/* release the device reference count */
11199484Sgarrett.damore@Sun.COM 	auimpl_dev_release(c->c_dev);
11209484Sgarrett.damore@Sun.COM 	c->c_dev = NULL;
11219484Sgarrett.damore@Sun.COM 
11229484Sgarrett.damore@Sun.COM 	mutex_destroy(&c->c_lock);
11239484Sgarrett.damore@Sun.COM 	cv_destroy(&c->c_cv);
11249484Sgarrett.damore@Sun.COM 
11259484Sgarrett.damore@Sun.COM 	audio_stream_fini(&c->c_istream);
11269484Sgarrett.damore@Sun.COM 	audio_stream_fini(&c->c_ostream);
11279484Sgarrett.damore@Sun.COM 	kmem_free(c, sizeof (*c));
11289484Sgarrett.damore@Sun.COM }
11299484Sgarrett.damore@Sun.COM 
11309484Sgarrett.damore@Sun.COM void
auimpl_client_activate(audio_client_t * c)113110570Sgdamore@opensolaris.org auimpl_client_activate(audio_client_t *c)
113210570Sgdamore@opensolaris.org {
113310570Sgdamore@opensolaris.org 	rw_enter(&auimpl_client_lock, RW_WRITER);
113410570Sgdamore@opensolaris.org 	c->c_is_active = B_TRUE;
113510570Sgdamore@opensolaris.org 	rw_exit(&auimpl_client_lock);
113610570Sgdamore@opensolaris.org }
113710570Sgdamore@opensolaris.org 
113810570Sgdamore@opensolaris.org void
auimpl_client_deactivate(audio_client_t * c)113910570Sgdamore@opensolaris.org auimpl_client_deactivate(audio_client_t *c)
114010570Sgdamore@opensolaris.org {
114110570Sgdamore@opensolaris.org 	rw_enter(&auimpl_client_lock, RW_WRITER);
114210570Sgdamore@opensolaris.org 	c->c_is_active = B_FALSE;
114310570Sgdamore@opensolaris.org 	rw_exit(&auimpl_client_lock);
114410570Sgdamore@opensolaris.org }
114510570Sgdamore@opensolaris.org 
114610570Sgdamore@opensolaris.org void
auclnt_close(audio_client_t * c)11479484Sgarrett.damore@Sun.COM auclnt_close(audio_client_t *c)
11489484Sgarrett.damore@Sun.COM {
11499484Sgarrett.damore@Sun.COM 	audio_dev_t	*d = c->c_dev;
11509484Sgarrett.damore@Sun.COM 
11519484Sgarrett.damore@Sun.COM 	/* stop the engines if they are running */
11529484Sgarrett.damore@Sun.COM 	auclnt_stop(&c->c_istream);
11539484Sgarrett.damore@Sun.COM 	auclnt_stop(&c->c_ostream);
11549484Sgarrett.damore@Sun.COM 
115510570Sgdamore@opensolaris.org 	rw_enter(&auimpl_client_lock, RW_WRITER);
11569484Sgarrett.damore@Sun.COM 	list_remove(&d->d_clients, c);
115710570Sgdamore@opensolaris.org 	rw_exit(&auimpl_client_lock);
11589484Sgarrett.damore@Sun.COM 
11599484Sgarrett.damore@Sun.COM 	mutex_enter(&c->c_lock);
11609484Sgarrett.damore@Sun.COM 	/* if in transition need to wait for other thread to release */
11619484Sgarrett.damore@Sun.COM 	while (c->c_refcnt) {
11629484Sgarrett.damore@Sun.COM 		cv_wait(&c->c_cv, &c->c_lock);
11639484Sgarrett.damore@Sun.COM 	}
11649484Sgarrett.damore@Sun.COM 	mutex_exit(&c->c_lock);
11659484Sgarrett.damore@Sun.COM 
11669484Sgarrett.damore@Sun.COM 	/* release any engines that we were holding */
11679484Sgarrett.damore@Sun.COM 	auimpl_engine_close(&c->c_ostream);
11689484Sgarrett.damore@Sun.COM 	auimpl_engine_close(&c->c_istream);
11699484Sgarrett.damore@Sun.COM }
11709484Sgarrett.damore@Sun.COM 
11719484Sgarrett.damore@Sun.COM audio_dev_t *
auclnt_hold_dev_by_index(int index)11729484Sgarrett.damore@Sun.COM auclnt_hold_dev_by_index(int index)
11739484Sgarrett.damore@Sun.COM {
11749484Sgarrett.damore@Sun.COM 	return (auimpl_dev_hold_by_index(index));
11759484Sgarrett.damore@Sun.COM }
11769484Sgarrett.damore@Sun.COM 
11779484Sgarrett.damore@Sun.COM void
auclnt_release_dev(audio_dev_t * dev)11789484Sgarrett.damore@Sun.COM auclnt_release_dev(audio_dev_t *dev)
11799484Sgarrett.damore@Sun.COM {
11809484Sgarrett.damore@Sun.COM 	auimpl_dev_release(dev);
11819484Sgarrett.damore@Sun.COM }
11829484Sgarrett.damore@Sun.COM 
11839484Sgarrett.damore@Sun.COM audio_client_t *
auclnt_hold_by_devt(dev_t dev)11849484Sgarrett.damore@Sun.COM auclnt_hold_by_devt(dev_t dev)
11859484Sgarrett.damore@Sun.COM {
11869484Sgarrett.damore@Sun.COM 	minor_t	mn = getminor(dev);
11879484Sgarrett.damore@Sun.COM 	major_t mj = getmajor(dev);
11889484Sgarrett.damore@Sun.COM 	list_t *list;
11899484Sgarrett.damore@Sun.COM 	audio_client_t *c;
11909484Sgarrett.damore@Sun.COM 
11919484Sgarrett.damore@Sun.COM 	list = &auimpl_clients;
11929484Sgarrett.damore@Sun.COM 	/* linked list search is kind of inefficient, but it works */
11939484Sgarrett.damore@Sun.COM 	rw_enter(&auimpl_client_lock, RW_READER);
11949484Sgarrett.damore@Sun.COM 	for (c = list_head(list); c != NULL; c = list_next(list, c)) {
11959484Sgarrett.damore@Sun.COM 		if ((c->c_major == mj) && (c->c_minor == mn)) {
11969484Sgarrett.damore@Sun.COM 			mutex_enter(&c->c_lock);
119710570Sgdamore@opensolaris.org 			if (c->c_is_active) {
11989484Sgarrett.damore@Sun.COM 				c->c_refcnt++;
11999484Sgarrett.damore@Sun.COM 				mutex_exit(&c->c_lock);
12009484Sgarrett.damore@Sun.COM 			} else {
12019484Sgarrett.damore@Sun.COM 				mutex_exit(&c->c_lock);
12029484Sgarrett.damore@Sun.COM 				c = NULL;
12039484Sgarrett.damore@Sun.COM 			}
12049484Sgarrett.damore@Sun.COM 			break;
12059484Sgarrett.damore@Sun.COM 		}
12069484Sgarrett.damore@Sun.COM 	}
12079484Sgarrett.damore@Sun.COM 	rw_exit(&auimpl_client_lock);
12089484Sgarrett.damore@Sun.COM 	return (c);
12099484Sgarrett.damore@Sun.COM }
12109484Sgarrett.damore@Sun.COM 
121111936Sgdamore@opensolaris.org int
auclnt_serialize(audio_client_t * c)121211936Sgdamore@opensolaris.org auclnt_serialize(audio_client_t *c)
121311936Sgdamore@opensolaris.org {
121411936Sgdamore@opensolaris.org 	mutex_enter(&c->c_lock);
121511936Sgdamore@opensolaris.org 	while (c->c_serialize) {
121611936Sgdamore@opensolaris.org 		if (cv_wait_sig(&c->c_cv, &c->c_lock) == 0) {
121711936Sgdamore@opensolaris.org 			mutex_exit(&c->c_lock);
121811936Sgdamore@opensolaris.org 			return (EINTR);
121911936Sgdamore@opensolaris.org 		}
122011936Sgdamore@opensolaris.org 	}
122111936Sgdamore@opensolaris.org 	c->c_serialize = B_TRUE;
122211936Sgdamore@opensolaris.org 	mutex_exit(&c->c_lock);
122311936Sgdamore@opensolaris.org 	return (0);
122411936Sgdamore@opensolaris.org }
122511936Sgdamore@opensolaris.org 
122611936Sgdamore@opensolaris.org void
auclnt_unserialize(audio_client_t * c)122711936Sgdamore@opensolaris.org auclnt_unserialize(audio_client_t *c)
122811936Sgdamore@opensolaris.org {
122911936Sgdamore@opensolaris.org 	mutex_enter(&c->c_lock);
123011936Sgdamore@opensolaris.org 	ASSERT(c->c_serialize);
123111936Sgdamore@opensolaris.org 	c->c_serialize = B_FALSE;
123211936Sgdamore@opensolaris.org 	cv_broadcast(&c->c_cv);
123311936Sgdamore@opensolaris.org 	mutex_exit(&c->c_lock);
123411936Sgdamore@opensolaris.org }
123511936Sgdamore@opensolaris.org 
123611936Sgdamore@opensolaris.org void
auclnt_hold(audio_client_t * c)123711936Sgdamore@opensolaris.org auclnt_hold(audio_client_t *c)
123811936Sgdamore@opensolaris.org {
123911936Sgdamore@opensolaris.org 	mutex_enter(&c->c_lock);
124011936Sgdamore@opensolaris.org 	c->c_refcnt++;
124111936Sgdamore@opensolaris.org 	mutex_exit(&c->c_lock);
124211936Sgdamore@opensolaris.org }
124311936Sgdamore@opensolaris.org 
12449484Sgarrett.damore@Sun.COM void
auclnt_release(audio_client_t * c)12459484Sgarrett.damore@Sun.COM auclnt_release(audio_client_t *c)
12469484Sgarrett.damore@Sun.COM {
12479484Sgarrett.damore@Sun.COM 	mutex_enter(&c->c_lock);
124810157Sgdamore@opensolaris.org 	ASSERT(c->c_refcnt > 0);
12499484Sgarrett.damore@Sun.COM 	c->c_refcnt--;
12509484Sgarrett.damore@Sun.COM 	if (c->c_refcnt == 0)
12519484Sgarrett.damore@Sun.COM 		cv_broadcast(&c->c_cv);
12529484Sgarrett.damore@Sun.COM 	mutex_exit(&c->c_lock);
12539484Sgarrett.damore@Sun.COM }
12549484Sgarrett.damore@Sun.COM 
125511936Sgdamore@opensolaris.org uint_t
auclnt_dev_get_serial(audio_dev_t * d)125610632Sgdamore@opensolaris.org auclnt_dev_get_serial(audio_dev_t *d)
125710632Sgdamore@opensolaris.org {
125810632Sgdamore@opensolaris.org 	return (d->d_serial);
125910632Sgdamore@opensolaris.org }
126010632Sgdamore@opensolaris.org 
12619484Sgarrett.damore@Sun.COM void
auclnt_dev_walk_clients(audio_dev_t * d,int (* walker)(audio_client_t *,void *),void * arg)12629484Sgarrett.damore@Sun.COM auclnt_dev_walk_clients(audio_dev_t *d,
12639484Sgarrett.damore@Sun.COM     int (*walker)(audio_client_t *, void *),
12649484Sgarrett.damore@Sun.COM     void *arg)
12659484Sgarrett.damore@Sun.COM {
12669484Sgarrett.damore@Sun.COM 	list_t		*l = &d->d_clients;
12679484Sgarrett.damore@Sun.COM 	audio_client_t	*c;
12689484Sgarrett.damore@Sun.COM 	int		rv;
12699484Sgarrett.damore@Sun.COM 
127010570Sgdamore@opensolaris.org 	rw_enter(&auimpl_client_lock, RW_READER);
12719484Sgarrett.damore@Sun.COM restart:
12729484Sgarrett.damore@Sun.COM 	for (c = list_head(l); c != NULL; c = list_next(l, c)) {
127310570Sgdamore@opensolaris.org 		if (!c->c_is_active)
127410570Sgdamore@opensolaris.org 			continue;
12759484Sgarrett.damore@Sun.COM 		rv = (walker(c, arg));
12769484Sgarrett.damore@Sun.COM 		if (rv == AUDIO_WALK_STOP) {
12779484Sgarrett.damore@Sun.COM 			break;
12789484Sgarrett.damore@Sun.COM 		} else if (rv == AUDIO_WALK_RESTART) {
12799484Sgarrett.damore@Sun.COM 			goto restart;
12809484Sgarrett.damore@Sun.COM 		}
12819484Sgarrett.damore@Sun.COM 	}
128210570Sgdamore@opensolaris.org 	rw_exit(&auimpl_client_lock);
12839484Sgarrett.damore@Sun.COM }
12849484Sgarrett.damore@Sun.COM 
12859484Sgarrett.damore@Sun.COM 
12869484Sgarrett.damore@Sun.COM int
auclnt_open(audio_client_t * c,int oflag)128712165Sgdamore@opensolaris.org auclnt_open(audio_client_t *c, int oflag)
12889484Sgarrett.damore@Sun.COM {
12899484Sgarrett.damore@Sun.COM 	audio_stream_t	*sp;
12909484Sgarrett.damore@Sun.COM 	audio_dev_t	*d = c->c_dev;
12919484Sgarrett.damore@Sun.COM 	int		rv = 0;
12929484Sgarrett.damore@Sun.COM 	int		flags;
12939484Sgarrett.damore@Sun.COM 
12949484Sgarrett.damore@Sun.COM 	flags = 0;
12959484Sgarrett.damore@Sun.COM 	if (oflag & FNDELAY)
12969484Sgarrett.damore@Sun.COM 		flags |= ENGINE_NDELAY;
12979484Sgarrett.damore@Sun.COM 
12989484Sgarrett.damore@Sun.COM 	if (oflag & FWRITE) {
12999484Sgarrett.damore@Sun.COM 		sp = &c->c_ostream;
130012165Sgdamore@opensolaris.org 		if ((rv = auimpl_engine_open(sp, flags | ENGINE_OUTPUT)) != 0)
13019484Sgarrett.damore@Sun.COM 			goto done;
13029484Sgarrett.damore@Sun.COM 	}
13039484Sgarrett.damore@Sun.COM 
13049484Sgarrett.damore@Sun.COM 	if (oflag & FREAD) {
13059484Sgarrett.damore@Sun.COM 		sp = &c->c_istream;
130612165Sgdamore@opensolaris.org 		if ((rv = auimpl_engine_open(sp, flags | ENGINE_INPUT)) != 0)
13079484Sgarrett.damore@Sun.COM 			goto done;
13089484Sgarrett.damore@Sun.COM 	}
13099484Sgarrett.damore@Sun.COM 
13109484Sgarrett.damore@Sun.COM done:
13119484Sgarrett.damore@Sun.COM 	if (rv != 0) {
13129484Sgarrett.damore@Sun.COM 		/* close any engines that we opened */
13139484Sgarrett.damore@Sun.COM 		auimpl_engine_close(&c->c_ostream);
13149484Sgarrett.damore@Sun.COM 		auimpl_engine_close(&c->c_istream);
13159484Sgarrett.damore@Sun.COM 	} else {
131610570Sgdamore@opensolaris.org 		rw_enter(&auimpl_client_lock, RW_WRITER);
13179484Sgarrett.damore@Sun.COM 		list_insert_tail(&d->d_clients, c);
13189484Sgarrett.damore@Sun.COM 		c->c_ostream.s_gain_master = d->d_pcmvol;
13199484Sgarrett.damore@Sun.COM 		c->c_istream.s_gain_master = 100;
132010570Sgdamore@opensolaris.org 		rw_exit(&auimpl_client_lock);
13219484Sgarrett.damore@Sun.COM 		auclnt_set_gain(&c->c_ostream, 100);
13229484Sgarrett.damore@Sun.COM 		auclnt_set_gain(&c->c_istream, 100);
13239484Sgarrett.damore@Sun.COM 	}
13249484Sgarrett.damore@Sun.COM 
13259484Sgarrett.damore@Sun.COM 	return (rv);
13269484Sgarrett.damore@Sun.COM }
13279484Sgarrett.damore@Sun.COM 
13289484Sgarrett.damore@Sun.COM minor_t
auclnt_get_minor(audio_client_t * c)13299484Sgarrett.damore@Sun.COM auclnt_get_minor(audio_client_t *c)
13309484Sgarrett.damore@Sun.COM {
13319484Sgarrett.damore@Sun.COM 	return (c->c_minor);
13329484Sgarrett.damore@Sun.COM }
13339484Sgarrett.damore@Sun.COM 
13349484Sgarrett.damore@Sun.COM minor_t
auclnt_get_original_minor(audio_client_t * c)13359484Sgarrett.damore@Sun.COM auclnt_get_original_minor(audio_client_t *c)
13369484Sgarrett.damore@Sun.COM {
13379484Sgarrett.damore@Sun.COM 	return (c->c_origminor);
13389484Sgarrett.damore@Sun.COM }
13399484Sgarrett.damore@Sun.COM 
13409484Sgarrett.damore@Sun.COM minor_t
auclnt_get_minor_type(audio_client_t * c)13419484Sgarrett.damore@Sun.COM auclnt_get_minor_type(audio_client_t *c)
13429484Sgarrett.damore@Sun.COM {
13439484Sgarrett.damore@Sun.COM 	return (c->c_origminor & AUDIO_MN_TYPE_MASK);
13449484Sgarrett.damore@Sun.COM }
13459484Sgarrett.damore@Sun.COM 
134610157Sgdamore@opensolaris.org queue_t *
auclnt_get_rq(audio_client_t * c)134710157Sgdamore@opensolaris.org auclnt_get_rq(audio_client_t *c)
134810157Sgdamore@opensolaris.org {
134910157Sgdamore@opensolaris.org 	return (c->c_rq);
135010157Sgdamore@opensolaris.org }
135110157Sgdamore@opensolaris.org 
135210157Sgdamore@opensolaris.org queue_t *
auclnt_get_wq(audio_client_t * c)135310157Sgdamore@opensolaris.org auclnt_get_wq(audio_client_t *c)
135410157Sgdamore@opensolaris.org {
135510157Sgdamore@opensolaris.org 	return (c->c_wq);
135610157Sgdamore@opensolaris.org }
135710157Sgdamore@opensolaris.org 
13589484Sgarrett.damore@Sun.COM pid_t
auclnt_get_pid(audio_client_t * c)13599484Sgarrett.damore@Sun.COM auclnt_get_pid(audio_client_t *c)
13609484Sgarrett.damore@Sun.COM {
13619484Sgarrett.damore@Sun.COM 	return (c->c_pid);
13629484Sgarrett.damore@Sun.COM }
13639484Sgarrett.damore@Sun.COM 
13649484Sgarrett.damore@Sun.COM cred_t *
auclnt_get_cred(audio_client_t * c)13659484Sgarrett.damore@Sun.COM auclnt_get_cred(audio_client_t *c)
13669484Sgarrett.damore@Sun.COM {
13679484Sgarrett.damore@Sun.COM 	return (c->c_cred);
13689484Sgarrett.damore@Sun.COM }
13699484Sgarrett.damore@Sun.COM 
13709484Sgarrett.damore@Sun.COM audio_dev_t *
auclnt_get_dev(audio_client_t * c)13719484Sgarrett.damore@Sun.COM auclnt_get_dev(audio_client_t *c)
13729484Sgarrett.damore@Sun.COM {
13739484Sgarrett.damore@Sun.COM 	return (c->c_dev);
13749484Sgarrett.damore@Sun.COM }
13759484Sgarrett.damore@Sun.COM 
13769484Sgarrett.damore@Sun.COM int
auclnt_get_dev_number(audio_dev_t * dev)13779484Sgarrett.damore@Sun.COM auclnt_get_dev_number(audio_dev_t *dev)
13789484Sgarrett.damore@Sun.COM {
13799484Sgarrett.damore@Sun.COM 	return (dev->d_number);
13809484Sgarrett.damore@Sun.COM }
13819484Sgarrett.damore@Sun.COM 
13829484Sgarrett.damore@Sun.COM int
auclnt_get_dev_index(audio_dev_t * dev)13839484Sgarrett.damore@Sun.COM auclnt_get_dev_index(audio_dev_t *dev)
13849484Sgarrett.damore@Sun.COM {
13859484Sgarrett.damore@Sun.COM 	return (dev->d_index);
13869484Sgarrett.damore@Sun.COM }
13879484Sgarrett.damore@Sun.COM 
13889484Sgarrett.damore@Sun.COM const char *
auclnt_get_dev_name(audio_dev_t * dev)13899484Sgarrett.damore@Sun.COM auclnt_get_dev_name(audio_dev_t *dev)
13909484Sgarrett.damore@Sun.COM {
13919484Sgarrett.damore@Sun.COM 	return (dev->d_name);
13929484Sgarrett.damore@Sun.COM }
13939484Sgarrett.damore@Sun.COM 
13949484Sgarrett.damore@Sun.COM const char *
auclnt_get_dev_driver(audio_dev_t * dev)13959484Sgarrett.damore@Sun.COM auclnt_get_dev_driver(audio_dev_t *dev)
13969484Sgarrett.damore@Sun.COM {
13979484Sgarrett.damore@Sun.COM 	return (ddi_driver_name(dev->d_dip));
13989484Sgarrett.damore@Sun.COM }
13999484Sgarrett.damore@Sun.COM 
14009484Sgarrett.damore@Sun.COM dev_info_t *
auclnt_get_dev_devinfo(audio_dev_t * dev)14019484Sgarrett.damore@Sun.COM auclnt_get_dev_devinfo(audio_dev_t *dev)
14029484Sgarrett.damore@Sun.COM {
14039484Sgarrett.damore@Sun.COM 	return (dev->d_dip);
14049484Sgarrett.damore@Sun.COM }
14059484Sgarrett.damore@Sun.COM 
14069484Sgarrett.damore@Sun.COM const char *
auclnt_get_dev_hw_info(audio_dev_t * dev,void ** iter)14079484Sgarrett.damore@Sun.COM auclnt_get_dev_hw_info(audio_dev_t *dev, void **iter)
14089484Sgarrett.damore@Sun.COM {
14099484Sgarrett.damore@Sun.COM 	struct audio_infostr *isp = *iter;
14109484Sgarrett.damore@Sun.COM 	if (isp == NULL) {
14119484Sgarrett.damore@Sun.COM 		isp = list_head(&dev->d_hwinfo);
14129484Sgarrett.damore@Sun.COM 	} else {
14139484Sgarrett.damore@Sun.COM 		isp = list_next(&dev->d_hwinfo, isp);
14149484Sgarrett.damore@Sun.COM 	}
14159484Sgarrett.damore@Sun.COM 
14169484Sgarrett.damore@Sun.COM 	*iter = isp;
14179484Sgarrett.damore@Sun.COM 	return (isp ? isp->i_line : NULL);
14189484Sgarrett.damore@Sun.COM }
14199484Sgarrett.damore@Sun.COM 
14209484Sgarrett.damore@Sun.COM int
auclnt_get_dev_instance(audio_dev_t * dev)14219484Sgarrett.damore@Sun.COM auclnt_get_dev_instance(audio_dev_t *dev)
14229484Sgarrett.damore@Sun.COM {
14239484Sgarrett.damore@Sun.COM 	return (dev->d_instance);
14249484Sgarrett.damore@Sun.COM }
14259484Sgarrett.damore@Sun.COM 
14269484Sgarrett.damore@Sun.COM const char *
auclnt_get_dev_description(audio_dev_t * dev)14279484Sgarrett.damore@Sun.COM auclnt_get_dev_description(audio_dev_t *dev)
14289484Sgarrett.damore@Sun.COM {
14299484Sgarrett.damore@Sun.COM 	return (dev->d_desc);
14309484Sgarrett.damore@Sun.COM }
14319484Sgarrett.damore@Sun.COM 
14329484Sgarrett.damore@Sun.COM const char *
auclnt_get_dev_version(audio_dev_t * dev)14339484Sgarrett.damore@Sun.COM auclnt_get_dev_version(audio_dev_t *dev)
14349484Sgarrett.damore@Sun.COM {
14359484Sgarrett.damore@Sun.COM 	return (dev->d_vers);
14369484Sgarrett.damore@Sun.COM }
14379484Sgarrett.damore@Sun.COM 
143811936Sgdamore@opensolaris.org uint_t
auclnt_get_dev_capab(audio_dev_t * dev)14399484Sgarrett.damore@Sun.COM auclnt_get_dev_capab(audio_dev_t *dev)
14409484Sgarrett.damore@Sun.COM {
14419484Sgarrett.damore@Sun.COM 	uint32_t	flags;
144211936Sgdamore@opensolaris.org 	uint_t		caps = 0;
14439484Sgarrett.damore@Sun.COM 
14449484Sgarrett.damore@Sun.COM 	flags = dev->d_flags;
14459484Sgarrett.damore@Sun.COM 
14469484Sgarrett.damore@Sun.COM 	if (flags & DEV_OUTPUT_CAP)
14479484Sgarrett.damore@Sun.COM 		caps |= AUDIO_CLIENT_CAP_PLAY;
14489484Sgarrett.damore@Sun.COM 	if (flags & DEV_INPUT_CAP)
14499484Sgarrett.damore@Sun.COM 		caps |= AUDIO_CLIENT_CAP_RECORD;
14509484Sgarrett.damore@Sun.COM 	if (flags & DEV_DUPLEX_CAP)
14519484Sgarrett.damore@Sun.COM 		caps |= AUDIO_CLIENT_CAP_DUPLEX;
14529484Sgarrett.damore@Sun.COM 
14539484Sgarrett.damore@Sun.COM 	/* AC3: deal with formats that don't support mixing */
14549484Sgarrett.damore@Sun.COM 
14559484Sgarrett.damore@Sun.COM 	return (caps);
14569484Sgarrett.damore@Sun.COM }
14579484Sgarrett.damore@Sun.COM 
14589484Sgarrett.damore@Sun.COM uint64_t
auclnt_get_samples(audio_stream_t * sp)14599484Sgarrett.damore@Sun.COM auclnt_get_samples(audio_stream_t *sp)
14609484Sgarrett.damore@Sun.COM {
14619484Sgarrett.damore@Sun.COM 	uint64_t	n;
14629484Sgarrett.damore@Sun.COM 
14639484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
14649484Sgarrett.damore@Sun.COM 	n = sp->s_samples;
14659484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
14669484Sgarrett.damore@Sun.COM 	return (n);
14679484Sgarrett.damore@Sun.COM }
14689484Sgarrett.damore@Sun.COM 
14699484Sgarrett.damore@Sun.COM void
auclnt_set_samples(audio_stream_t * sp,uint64_t n)14709484Sgarrett.damore@Sun.COM auclnt_set_samples(audio_stream_t *sp, uint64_t n)
14719484Sgarrett.damore@Sun.COM {
14729484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
14739484Sgarrett.damore@Sun.COM 	sp->s_samples = n;
14749484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
14759484Sgarrett.damore@Sun.COM }
14769484Sgarrett.damore@Sun.COM 
14779484Sgarrett.damore@Sun.COM uint64_t
auclnt_get_errors(audio_stream_t * sp)14789484Sgarrett.damore@Sun.COM auclnt_get_errors(audio_stream_t *sp)
14799484Sgarrett.damore@Sun.COM {
14809484Sgarrett.damore@Sun.COM 	uint64_t	n;
14819484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
14829484Sgarrett.damore@Sun.COM 	n = sp->s_errors;
14839484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
14849484Sgarrett.damore@Sun.COM 	return (n);
14859484Sgarrett.damore@Sun.COM }
14869484Sgarrett.damore@Sun.COM 
14879484Sgarrett.damore@Sun.COM void
auclnt_set_errors(audio_stream_t * sp,uint64_t n)14889484Sgarrett.damore@Sun.COM auclnt_set_errors(audio_stream_t *sp, uint64_t n)
14899484Sgarrett.damore@Sun.COM {
14909484Sgarrett.damore@Sun.COM 	mutex_enter(&sp->s_lock);
14919484Sgarrett.damore@Sun.COM 	sp->s_errors = n;
14929484Sgarrett.damore@Sun.COM 	mutex_exit(&sp->s_lock);
14939484Sgarrett.damore@Sun.COM }
14949484Sgarrett.damore@Sun.COM 
14959484Sgarrett.damore@Sun.COM void
auclnt_register_ops(minor_t minor,audio_client_ops_t * ops)14969484Sgarrett.damore@Sun.COM auclnt_register_ops(minor_t minor, audio_client_ops_t *ops)
14979484Sgarrett.damore@Sun.COM {
14989484Sgarrett.damore@Sun.COM 	/* we control minor number allocations, no need for runtime checks */
14999484Sgarrett.damore@Sun.COM 	ASSERT(minor <= AUDIO_MN_TYPE_MASK);
15009484Sgarrett.damore@Sun.COM 
15019484Sgarrett.damore@Sun.COM 	audio_client_ops[minor] = ops;
15029484Sgarrett.damore@Sun.COM }
15039484Sgarrett.damore@Sun.COM 
15049484Sgarrett.damore@Sun.COM int
auimpl_create_minors(audio_dev_t * d)15059484Sgarrett.damore@Sun.COM auimpl_create_minors(audio_dev_t *d)
15069484Sgarrett.damore@Sun.COM {
15079484Sgarrett.damore@Sun.COM 	char			path[MAXPATHLEN];
15089484Sgarrett.damore@Sun.COM 	int			rv = 0;
15099484Sgarrett.damore@Sun.COM 	minor_t			minor;
15109484Sgarrett.damore@Sun.COM 	audio_client_ops_t	*ops;
15119484Sgarrett.damore@Sun.COM 	char			*nt;
15129484Sgarrett.damore@Sun.COM 
15139484Sgarrett.damore@Sun.COM 	for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) {
15149484Sgarrett.damore@Sun.COM 
15159484Sgarrett.damore@Sun.COM 		if ((ops = audio_client_ops[i]) == NULL)
15169484Sgarrett.damore@Sun.COM 			continue;
15179484Sgarrett.damore@Sun.COM 
15189484Sgarrett.damore@Sun.COM 		if (ops->aco_dev_init != NULL)
15199484Sgarrett.damore@Sun.COM 			d->d_minor_data[i] = ops->aco_dev_init(d);
15209484Sgarrett.damore@Sun.COM 
15219484Sgarrett.damore@Sun.COM 		switch (i) {
15229484Sgarrett.damore@Sun.COM 		case AUDIO_MINOR_SNDSTAT:
15239484Sgarrett.damore@Sun.COM 			if (!(d->d_flags & DEV_SNDSTAT_CAP)) {
15249484Sgarrett.damore@Sun.COM 				continue;
15259484Sgarrett.damore@Sun.COM 			}
15269484Sgarrett.damore@Sun.COM 			nt = DDI_PSEUDO;
15279484Sgarrett.damore@Sun.COM 			break;
15289484Sgarrett.damore@Sun.COM 
15299484Sgarrett.damore@Sun.COM 		default:
15309484Sgarrett.damore@Sun.COM 			if (!(d->d_flags & (DEV_INPUT_CAP| DEV_OUTPUT_CAP))) {
15319484Sgarrett.damore@Sun.COM 				continue;
15329484Sgarrett.damore@Sun.COM 			}
15339484Sgarrett.damore@Sun.COM 			nt = DDI_NT_AUDIO;
15349484Sgarrett.damore@Sun.COM 			break;
15359484Sgarrett.damore@Sun.COM 		}
15369484Sgarrett.damore@Sun.COM 
15379484Sgarrett.damore@Sun.COM 		if (ops->aco_minor_prefix != NULL) {
15389484Sgarrett.damore@Sun.COM 
15399484Sgarrett.damore@Sun.COM 			minor = AUDIO_MKMN(d->d_instance, i);
15409484Sgarrett.damore@Sun.COM 			(void) snprintf(path, sizeof (path),
15419484Sgarrett.damore@Sun.COM 			    "%s%d", ops->aco_minor_prefix, d->d_instance);
15429484Sgarrett.damore@Sun.COM 
15439484Sgarrett.damore@Sun.COM 			rv = ddi_create_minor_node(d->d_dip, path, S_IFCHR,
15449484Sgarrett.damore@Sun.COM 			    minor, nt, 0);
15459484Sgarrett.damore@Sun.COM 
15469484Sgarrett.damore@Sun.COM 			if (rv != 0)
15479484Sgarrett.damore@Sun.COM 				break;
15489484Sgarrett.damore@Sun.COM 		}
15499484Sgarrett.damore@Sun.COM 	}
15509484Sgarrett.damore@Sun.COM 	return (rv);
15519484Sgarrett.damore@Sun.COM }
15529484Sgarrett.damore@Sun.COM 
15539484Sgarrett.damore@Sun.COM void
auimpl_remove_minors(audio_dev_t * d)15549484Sgarrett.damore@Sun.COM auimpl_remove_minors(audio_dev_t *d)
15559484Sgarrett.damore@Sun.COM {
15569484Sgarrett.damore@Sun.COM 	char			path[MAXPATHLEN];
15579484Sgarrett.damore@Sun.COM 	audio_client_ops_t	*ops;
15589484Sgarrett.damore@Sun.COM 
15599484Sgarrett.damore@Sun.COM 	for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) {
15609484Sgarrett.damore@Sun.COM 		if ((ops = audio_client_ops[i]) == NULL)
15619484Sgarrett.damore@Sun.COM 			continue;
15629484Sgarrett.damore@Sun.COM 		if (ops->aco_minor_prefix != NULL) {
15639484Sgarrett.damore@Sun.COM 			(void) snprintf(path, sizeof (path), "%s%d",
15649484Sgarrett.damore@Sun.COM 			    ops->aco_minor_prefix, d->d_instance);
15659484Sgarrett.damore@Sun.COM 			(void) ddi_remove_minor_node(d->d_dip, path);
15669484Sgarrett.damore@Sun.COM 		}
15679484Sgarrett.damore@Sun.COM 
15689484Sgarrett.damore@Sun.COM 		if (ops->aco_dev_fini != NULL)
15699484Sgarrett.damore@Sun.COM 			ops->aco_dev_fini(d->d_minor_data[i]);
15709484Sgarrett.damore@Sun.COM 	}
15719484Sgarrett.damore@Sun.COM }
15729484Sgarrett.damore@Sun.COM 
15739484Sgarrett.damore@Sun.COM void *
auclnt_get_dev_minor_data(audio_dev_t * d,minor_t mn)15749484Sgarrett.damore@Sun.COM auclnt_get_dev_minor_data(audio_dev_t *d, minor_t mn)
15759484Sgarrett.damore@Sun.COM {
15769484Sgarrett.damore@Sun.COM 	ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS));
15779484Sgarrett.damore@Sun.COM 	return (d->d_minor_data[mn]);
15789484Sgarrett.damore@Sun.COM }
15799484Sgarrett.damore@Sun.COM 
15809484Sgarrett.damore@Sun.COM void *
auclnt_get_minor_data(audio_client_t * c,minor_t mn)15819484Sgarrett.damore@Sun.COM auclnt_get_minor_data(audio_client_t *c, minor_t mn)
15829484Sgarrett.damore@Sun.COM {
15839484Sgarrett.damore@Sun.COM 	ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS));
15849484Sgarrett.damore@Sun.COM 	return (c->c_dev->d_minor_data[mn]);
15859484Sgarrett.damore@Sun.COM }
15869484Sgarrett.damore@Sun.COM 
15879484Sgarrett.damore@Sun.COM /*
15889484Sgarrett.damore@Sun.COM  * This will walk all controls registered to a clients device and callback
15899484Sgarrett.damore@Sun.COM  * to walker for each one with its audio_ctrl. Note this data
15909484Sgarrett.damore@Sun.COM  * must be considered read only by walker.
15919484Sgarrett.damore@Sun.COM  *
15929484Sgarrett.damore@Sun.COM  * Note that walk_func may return values to continue (AUDIO_WALK_CONTINUE)
15939484Sgarrett.damore@Sun.COM  * or stop walk (AUDIO_WALK_STOP).
15949484Sgarrett.damore@Sun.COM  *
15959484Sgarrett.damore@Sun.COM  */
15969484Sgarrett.damore@Sun.COM void
auclnt_walk_controls(audio_dev_t * d,int (* walker)(audio_ctrl_t *,void *),void * arg)15979484Sgarrett.damore@Sun.COM auclnt_walk_controls(audio_dev_t *d,
15989484Sgarrett.damore@Sun.COM     int (*walker)(audio_ctrl_t *, void *),
15999484Sgarrett.damore@Sun.COM     void *arg)
16009484Sgarrett.damore@Sun.COM {
16019484Sgarrett.damore@Sun.COM 	audio_ctrl_t *ctrl;
16029484Sgarrett.damore@Sun.COM 
160311936Sgdamore@opensolaris.org 	mutex_enter(&d->d_ctrl_lock);
16049484Sgarrett.damore@Sun.COM 	for (ctrl = list_head(&d->d_controls); ctrl;
16059484Sgarrett.damore@Sun.COM 	    ctrl = list_next(&d->d_controls, ctrl)) {
16069484Sgarrett.damore@Sun.COM 		if (walker(ctrl, arg) == AUDIO_WALK_STOP)
16079484Sgarrett.damore@Sun.COM 			break;
16089484Sgarrett.damore@Sun.COM 	}
160911936Sgdamore@opensolaris.org 	mutex_exit(&d->d_ctrl_lock);
16109484Sgarrett.damore@Sun.COM }
16119484Sgarrett.damore@Sun.COM 
16129484Sgarrett.damore@Sun.COM /*
16139484Sgarrett.damore@Sun.COM  * This will search all controls attached to an
16149484Sgarrett.damore@Sun.COM  * audio device for a control with the desired name.
16159484Sgarrett.damore@Sun.COM  *
16169484Sgarrett.damore@Sun.COM  * d    - the audio device to look on
16179484Sgarrett.damore@Sun.COM  * name - name of the control being looked for.
16189484Sgarrett.damore@Sun.COM  *
16199484Sgarrett.damore@Sun.COM  * On successful return a ctrl handle will be returned. On
16209484Sgarrett.damore@Sun.COM  * failure NULL is returned.
16219484Sgarrett.damore@Sun.COM  */
16229484Sgarrett.damore@Sun.COM audio_ctrl_t *
auclnt_find_control(audio_dev_t * d,const char * name)16239484Sgarrett.damore@Sun.COM auclnt_find_control(audio_dev_t *d, const char *name)
16249484Sgarrett.damore@Sun.COM {
16259484Sgarrett.damore@Sun.COM 	audio_ctrl_t *ctrl;
16269484Sgarrett.damore@Sun.COM 
16279484Sgarrett.damore@Sun.COM 	/* Verify argument */
16289484Sgarrett.damore@Sun.COM 	ASSERT(d);
16299484Sgarrett.damore@Sun.COM 
163011936Sgdamore@opensolaris.org 	mutex_enter(&d->d_ctrl_lock);
16319484Sgarrett.damore@Sun.COM 	for (ctrl = list_head(&d->d_controls); ctrl;
16329484Sgarrett.damore@Sun.COM 	    ctrl = list_next(&d->d_controls, ctrl)) {
16339484Sgarrett.damore@Sun.COM 		if (strcmp(ctrl->ctrl_name, name) == 0) {
163411936Sgdamore@opensolaris.org 			mutex_exit(&d->d_ctrl_lock);
16359484Sgarrett.damore@Sun.COM 			return (ctrl);
16369484Sgarrett.damore@Sun.COM 		}
16379484Sgarrett.damore@Sun.COM 	}
163811936Sgdamore@opensolaris.org 	mutex_exit(&d->d_ctrl_lock);
16399484Sgarrett.damore@Sun.COM 	return (NULL);
16409484Sgarrett.damore@Sun.COM }
16419484Sgarrett.damore@Sun.COM 
16429484Sgarrett.damore@Sun.COM /*
16439484Sgarrett.damore@Sun.COM  * Given a known control, get its attributes.
16449484Sgarrett.damore@Sun.COM  *
16459484Sgarrett.damore@Sun.COM  * The caller must supply a audio_ctrl_desc_t structure.  Also the
16469484Sgarrett.damore@Sun.COM  * values in the structure are ignored when making the call and filled
16479484Sgarrett.damore@Sun.COM  * in by this function. All data pointed to by elements of desc should
16489484Sgarrett.damore@Sun.COM  * be assumed read only.
16499484Sgarrett.damore@Sun.COM  *
16509484Sgarrett.damore@Sun.COM  * If an error occurs then a non-zero is returned.
16519484Sgarrett.damore@Sun.COM  *
16529484Sgarrett.damore@Sun.COM  */
16539484Sgarrett.damore@Sun.COM int
auclnt_control_describe(audio_ctrl_t * ctrl,audio_ctrl_desc_t * desc)16549484Sgarrett.damore@Sun.COM auclnt_control_describe(audio_ctrl_t *ctrl, audio_ctrl_desc_t *desc)
16559484Sgarrett.damore@Sun.COM {
16569484Sgarrett.damore@Sun.COM 	ASSERT(ctrl);
16579484Sgarrett.damore@Sun.COM 	ASSERT(desc);
16589484Sgarrett.damore@Sun.COM 
16599484Sgarrett.damore@Sun.COM 	bcopy(&ctrl->ctrl_des, desc, sizeof (*desc));
16609484Sgarrett.damore@Sun.COM 	return (0);
16619484Sgarrett.damore@Sun.COM }
16629484Sgarrett.damore@Sun.COM 
16639484Sgarrett.damore@Sun.COM int
auclnt_control_read(audio_ctrl_t * ctrl,uint64_t * value)16649484Sgarrett.damore@Sun.COM auclnt_control_read(audio_ctrl_t *ctrl, uint64_t *value)
16659484Sgarrett.damore@Sun.COM {
16669484Sgarrett.damore@Sun.COM 	return (audio_control_read(ctrl, value));
16679484Sgarrett.damore@Sun.COM }
16689484Sgarrett.damore@Sun.COM 
16699484Sgarrett.damore@Sun.COM int
auclnt_control_write(audio_ctrl_t * ctrl,uint64_t value)16709484Sgarrett.damore@Sun.COM auclnt_control_write(audio_ctrl_t *ctrl, uint64_t value)
16719484Sgarrett.damore@Sun.COM {
16729484Sgarrett.damore@Sun.COM 	return (audio_control_write(ctrl, value));
16739484Sgarrett.damore@Sun.COM }
16749484Sgarrett.damore@Sun.COM 
16759484Sgarrett.damore@Sun.COM void
auclnt_warn(audio_client_t * c,const char * fmt,...)16769484Sgarrett.damore@Sun.COM auclnt_warn(audio_client_t *c, const char *fmt, ...)
16779484Sgarrett.damore@Sun.COM {
16789484Sgarrett.damore@Sun.COM 	va_list va;
16799484Sgarrett.damore@Sun.COM 
16809484Sgarrett.damore@Sun.COM 	va_start(va, fmt);
16819484Sgarrett.damore@Sun.COM 	auimpl_dev_vwarn(c ? c->c_dev : NULL, fmt, va);
16829484Sgarrett.damore@Sun.COM 	va_end(va);
16839484Sgarrett.damore@Sun.COM }
1684