188447a05SGarrett D'Amore /*
288447a05SGarrett D'Amore * CDDL HEADER START
388447a05SGarrett D'Amore *
488447a05SGarrett D'Amore * The contents of this file are subject to the terms of the
588447a05SGarrett D'Amore * Common Development and Distribution License (the "License").
688447a05SGarrett D'Amore * You may not use this file except in compliance with the License.
788447a05SGarrett D'Amore *
888447a05SGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
988447a05SGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
1088447a05SGarrett D'Amore * See the License for the specific language governing permissions
1188447a05SGarrett D'Amore * and limitations under the License.
1288447a05SGarrett D'Amore *
1388447a05SGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
1488447a05SGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1588447a05SGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
1688447a05SGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
1788447a05SGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
1888447a05SGarrett D'Amore *
1988447a05SGarrett D'Amore * CDDL HEADER END
2088447a05SGarrett D'Amore */
2188447a05SGarrett D'Amore /*
2288447a05SGarrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
2388447a05SGarrett D'Amore *
242c30fa45SGarrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2588447a05SGarrett D'Amore */
2688447a05SGarrett D'Amore
2788447a05SGarrett D'Amore #include <sys/types.h>
2888447a05SGarrett D'Amore #include <sys/sysmacros.h>
2988447a05SGarrett D'Amore #include <sys/list.h>
3088447a05SGarrett D'Amore #include <sys/file.h>
3188447a05SGarrett D'Amore #include <sys/open.h>
3288447a05SGarrett D'Amore #include <sys/stat.h>
3388447a05SGarrett D'Amore #include <sys/errno.h>
3488447a05SGarrett D'Amore #include <sys/atomic.h>
3588447a05SGarrett D'Amore #include <sys/ddi.h>
3688447a05SGarrett D'Amore #include <sys/sunddi.h>
3788447a05SGarrett D'Amore
3888447a05SGarrett D'Amore #include "audio_impl.h"
3988447a05SGarrett D'Amore
4088447a05SGarrett D'Amore /*
4188447a05SGarrett D'Amore * Audio Client implementation.
4288447a05SGarrett D'Amore */
4388447a05SGarrett D'Amore
4488447a05SGarrett D'Amore /*
4588447a05SGarrett D'Amore * Attenuation table for dB->linear conversion. Indexed in steps of
4688447a05SGarrett D'Amore * 0.5 dB. Table size is 25 dB (first entry is handled as mute).
4788447a05SGarrett D'Amore *
4888447a05SGarrett D'Amore * Notably, the last item in table is taken as 0 dB (i.e. maximum volume).
4988447a05SGarrett D'Amore *
5088447a05SGarrett D'Amore * Table contents can be calculated as follows (requires sunmath library):
5188447a05SGarrett D'Amore *
5288447a05SGarrett D'Amore * scale = AUDIO_VOL_SCALE;
5388447a05SGarrett D'Amore * for (i = -50; i <= 0; i++) {
5488447a05SGarrett D'Amore * x = exp10(0.05 * i);
5588447a05SGarrett D'Amore * printf("%d: %f %.0f\n", i, x, trunc(x * scale));
5688447a05SGarrett D'Amore * }
5788447a05SGarrett D'Amore *
5888447a05SGarrett D'Amore */
5988447a05SGarrett D'Amore
6053a539a7SGarrett D'Amore static const uint16_t auimpl_db_table[AUDIO_DB_SIZE + 1] = {
6188447a05SGarrett D'Amore 0, 0, 1, 1, 1, 1, 1, 1, 2, 2,
6288447a05SGarrett D'Amore 2, 2, 3, 3, 4, 4, 5, 5, 6, 7,
6388447a05SGarrett D'Amore 8, 9, 10, 11, 12, 14, 16, 18, 20, 22,
6488447a05SGarrett D'Amore 25, 28, 32, 36, 40, 45, 51, 57, 64, 72,
6588447a05SGarrett D'Amore 80, 90, 101, 114, 128, 143, 161, 181, 203, 228,
6688447a05SGarrett D'Amore 256
6788447a05SGarrett D'Amore };
6888447a05SGarrett D'Amore
6953a539a7SGarrett D'Amore static list_t auimpl_clients;
7053a539a7SGarrett D'Amore static krwlock_t auimpl_client_lock;
7153a539a7SGarrett D'Amore static audio_client_ops_t *audio_client_ops[AUDIO_MN_TYPE_MASK + 1];
7253a539a7SGarrett D'Amore
7388447a05SGarrett D'Amore void *
auclnt_get_private(audio_client_t * c)7488447a05SGarrett D'Amore auclnt_get_private(audio_client_t *c)
7588447a05SGarrett D'Amore {
7688447a05SGarrett D'Amore return (c->c_private);
7788447a05SGarrett D'Amore }
7888447a05SGarrett D'Amore
7988447a05SGarrett D'Amore void
auclnt_set_private(audio_client_t * c,void * private)8088447a05SGarrett D'Amore auclnt_set_private(audio_client_t *c, void *private)
8188447a05SGarrett D'Amore {
8288447a05SGarrett D'Amore c->c_private = private;
8388447a05SGarrett D'Amore }
8488447a05SGarrett D'Amore
8588447a05SGarrett D'Amore int
auclnt_set_rate(audio_stream_t * sp,int rate)8688447a05SGarrett D'Amore auclnt_set_rate(audio_stream_t *sp, int rate)
8788447a05SGarrett D'Amore {
8888447a05SGarrett D'Amore audio_parms_t parms;
8988447a05SGarrett D'Amore int rv = 0;
9088447a05SGarrett D'Amore
9188447a05SGarrett D'Amore /* basic sanity checks! */
9288447a05SGarrett D'Amore if ((rate < 5000) || (rate > 192000)) {
9388447a05SGarrett D'Amore return (EINVAL);
9488447a05SGarrett D'Amore }
952c30fa45SGarrett D'Amore if (rate != sp->s_user_parms->p_rate) {
9688447a05SGarrett D'Amore parms.p_rate = rate;
972c30fa45SGarrett D'Amore rv = auimpl_engine_setup(sp, 0, &parms, FORMAT_MSK_RATE);
9888447a05SGarrett D'Amore }
9988447a05SGarrett D'Amore return (rv);
10088447a05SGarrett D'Amore }
10188447a05SGarrett D'Amore
10288447a05SGarrett D'Amore int
auclnt_get_rate(audio_stream_t * sp)10388447a05SGarrett D'Amore auclnt_get_rate(audio_stream_t *sp)
10488447a05SGarrett D'Amore {
10588447a05SGarrett D'Amore return (sp->s_user_parms->p_rate);
10688447a05SGarrett D'Amore }
10788447a05SGarrett D'Amore
10868c47f65SGarrett D'Amore uint_t
auclnt_get_fragsz(audio_stream_t * sp)10988447a05SGarrett D'Amore auclnt_get_fragsz(audio_stream_t *sp)
11088447a05SGarrett D'Amore {
11188447a05SGarrett D'Amore return (sp->s_fragbytes);
11288447a05SGarrett D'Amore }
11388447a05SGarrett D'Amore
11468c47f65SGarrett D'Amore uint_t
auclnt_get_framesz(audio_stream_t * sp)11588447a05SGarrett D'Amore auclnt_get_framesz(audio_stream_t *sp)
11688447a05SGarrett D'Amore {
11788447a05SGarrett D'Amore return (sp->s_framesz);
11888447a05SGarrett D'Amore }
11988447a05SGarrett D'Amore
12068c47f65SGarrett D'Amore uint_t
auclnt_get_nfrags(audio_stream_t * sp)12188447a05SGarrett D'Amore auclnt_get_nfrags(audio_stream_t *sp)
12288447a05SGarrett D'Amore {
12388447a05SGarrett D'Amore return (sp->s_nfrags);
12488447a05SGarrett D'Amore }
12588447a05SGarrett D'Amore
12668c47f65SGarrett D'Amore uint_t
auclnt_get_nframes(audio_stream_t * sp)12788447a05SGarrett D'Amore auclnt_get_nframes(audio_stream_t *sp)
12888447a05SGarrett D'Amore {
12988447a05SGarrett D'Amore return (sp->s_nframes);
13088447a05SGarrett D'Amore }
13188447a05SGarrett D'Amore
132a702341cSGarrett D'Amore void
auclnt_set_latency(audio_stream_t * sp,uint_t frags,uint_t bytes)13368c47f65SGarrett D'Amore auclnt_set_latency(audio_stream_t *sp, uint_t frags, uint_t bytes)
134a702341cSGarrett D'Amore {
135a702341cSGarrett D'Amore mutex_enter(&sp->s_lock);
136a702341cSGarrett D'Amore sp->s_hintfrags = (uint16_t)frags;
137a702341cSGarrett D'Amore sp->s_hintsz = bytes;
138a702341cSGarrett D'Amore mutex_exit(&sp->s_lock);
139a702341cSGarrett D'Amore }
140a702341cSGarrett D'Amore
14188447a05SGarrett D'Amore uint64_t
auclnt_get_head(audio_stream_t * sp)14288447a05SGarrett D'Amore auclnt_get_head(audio_stream_t *sp)
14388447a05SGarrett D'Amore {
14488447a05SGarrett D'Amore return (sp->s_head);
14588447a05SGarrett D'Amore }
14688447a05SGarrett D'Amore
14788447a05SGarrett D'Amore uint64_t
auclnt_get_tail(audio_stream_t * sp)14888447a05SGarrett D'Amore auclnt_get_tail(audio_stream_t *sp)
14988447a05SGarrett D'Amore {
15088447a05SGarrett D'Amore return (sp->s_tail);
15188447a05SGarrett D'Amore }
15288447a05SGarrett D'Amore
15368c47f65SGarrett D'Amore uint_t
auclnt_get_hidx(audio_stream_t * sp)15488447a05SGarrett D'Amore auclnt_get_hidx(audio_stream_t *sp)
15588447a05SGarrett D'Amore {
15688447a05SGarrett D'Amore return (sp->s_hidx);
15788447a05SGarrett D'Amore }
15888447a05SGarrett D'Amore
15968c47f65SGarrett D'Amore uint_t
auclnt_get_tidx(audio_stream_t * sp)16088447a05SGarrett D'Amore auclnt_get_tidx(audio_stream_t *sp)
16188447a05SGarrett D'Amore {
16288447a05SGarrett D'Amore return (sp->s_tidx);
16388447a05SGarrett D'Amore }
16488447a05SGarrett D'Amore
16588447a05SGarrett D'Amore audio_stream_t *
auclnt_input_stream(audio_client_t * c)16688447a05SGarrett D'Amore auclnt_input_stream(audio_client_t *c)
16788447a05SGarrett D'Amore {
16888447a05SGarrett D'Amore return (&c->c_istream);
16988447a05SGarrett D'Amore }
17088447a05SGarrett D'Amore
17188447a05SGarrett D'Amore audio_stream_t *
auclnt_output_stream(audio_client_t * c)17288447a05SGarrett D'Amore auclnt_output_stream(audio_client_t *c)
17388447a05SGarrett D'Amore {
17488447a05SGarrett D'Amore return (&c->c_ostream);
17588447a05SGarrett D'Amore }
17688447a05SGarrett D'Amore
17768c47f65SGarrett D'Amore uint_t
auclnt_get_count(audio_stream_t * sp)17888447a05SGarrett D'Amore auclnt_get_count(audio_stream_t *sp)
17988447a05SGarrett D'Amore {
18068c47f65SGarrett D'Amore uint_t count;
18188447a05SGarrett D'Amore
18288447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
18388447a05SGarrett D'Amore ASSERT((sp->s_head - sp->s_tail) <= sp->s_nframes);
18468c47f65SGarrett D'Amore count = (uint_t)(sp->s_head - sp->s_tail);
18588447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
18688447a05SGarrett D'Amore
18788447a05SGarrett D'Amore return (count);
18888447a05SGarrett D'Amore }
18988447a05SGarrett D'Amore
19068c47f65SGarrett D'Amore uint_t
auclnt_consume(audio_stream_t * sp,uint_t n)19168c47f65SGarrett D'Amore auclnt_consume(audio_stream_t *sp, uint_t n)
19288447a05SGarrett D'Amore {
19388447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
19488447a05SGarrett D'Amore
19588447a05SGarrett D'Amore ASSERT(sp == &sp->s_client->c_istream);
19688447a05SGarrett D'Amore n = max(n, sp->s_head - sp->s_tail);
19788447a05SGarrett D'Amore sp->s_tail += n;
19888447a05SGarrett D'Amore sp->s_tidx += n;
19988447a05SGarrett D'Amore if (sp->s_tidx >= sp->s_nframes) {
20088447a05SGarrett D'Amore sp->s_tidx -= sp->s_nframes;
20188447a05SGarrett D'Amore }
20288447a05SGarrett D'Amore
20388447a05SGarrett D'Amore ASSERT(sp->s_tail <= sp->s_head);
20488447a05SGarrett D'Amore ASSERT(sp->s_hidx < sp->s_nframes);
20588447a05SGarrett D'Amore
20688447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
20788447a05SGarrett D'Amore
20888447a05SGarrett D'Amore return (n);
20988447a05SGarrett D'Amore }
21088447a05SGarrett D'Amore
21168c47f65SGarrett D'Amore uint_t
auclnt_consume_data(audio_stream_t * sp,caddr_t dst,uint_t n)21268c47f65SGarrett D'Amore auclnt_consume_data(audio_stream_t *sp, caddr_t dst, uint_t n)
21388447a05SGarrett D'Amore {
21468c47f65SGarrett D'Amore uint_t nframes;
21568c47f65SGarrett D'Amore uint_t framesz;
21668c47f65SGarrett D'Amore uint_t cnt;
21788447a05SGarrett D'Amore caddr_t data;
21888447a05SGarrett D'Amore
21988447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
22088447a05SGarrett D'Amore
22188447a05SGarrett D'Amore nframes = sp->s_nframes;
22288447a05SGarrett D'Amore framesz = sp->s_framesz;
22388447a05SGarrett D'Amore
22488447a05SGarrett D'Amore ASSERT(sp == &sp->s_client->c_istream);
22588447a05SGarrett D'Amore ASSERT(sp->s_head >= sp->s_tail);
22688447a05SGarrett D'Amore ASSERT(sp->s_tidx < nframes);
22788447a05SGarrett D'Amore ASSERT(sp->s_hidx < nframes);
22888447a05SGarrett D'Amore
22988447a05SGarrett D'Amore cnt = n = min(n, sp->s_head - sp->s_tail);
23088447a05SGarrett D'Amore data = sp->s_data + (sp->s_tidx * framesz);
23188447a05SGarrett D'Amore do {
23268c47f65SGarrett D'Amore uint_t nf, nb;
23388447a05SGarrett D'Amore
23488447a05SGarrett D'Amore nf = min(nframes - sp->s_tidx, n);
23588447a05SGarrett D'Amore nb = nf * framesz;
23688447a05SGarrett D'Amore
23788447a05SGarrett D'Amore bcopy(data, dst, nb);
23888447a05SGarrett D'Amore dst += nb;
23988447a05SGarrett D'Amore data += nb;
24088447a05SGarrett D'Amore
24188447a05SGarrett D'Amore n -= nf;
24288447a05SGarrett D'Amore sp->s_tail += nf;
24388447a05SGarrett D'Amore sp->s_tidx += nf;
24488447a05SGarrett D'Amore if (sp->s_tidx == nframes) {
24588447a05SGarrett D'Amore sp->s_tidx = 0;
24688447a05SGarrett D'Amore data = sp->s_data;
24788447a05SGarrett D'Amore }
24888447a05SGarrett D'Amore } while (n);
24988447a05SGarrett D'Amore
25088447a05SGarrett D'Amore ASSERT(sp->s_tail <= sp->s_head);
25188447a05SGarrett D'Amore ASSERT(sp->s_tidx < nframes);
25288447a05SGarrett D'Amore
25388447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
25488447a05SGarrett D'Amore
25588447a05SGarrett D'Amore return (cnt);
25688447a05SGarrett D'Amore }
25788447a05SGarrett D'Amore
25868c47f65SGarrett D'Amore uint_t
auclnt_produce(audio_stream_t * sp,uint_t n)25968c47f65SGarrett D'Amore auclnt_produce(audio_stream_t *sp, uint_t n)
26088447a05SGarrett D'Amore {
26188447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
26288447a05SGarrett D'Amore
26388447a05SGarrett D'Amore ASSERT(sp == &sp->s_client->c_ostream);
26488447a05SGarrett D'Amore n = max(n, sp->s_nframes - (sp->s_head - sp->s_tail));
26588447a05SGarrett D'Amore sp->s_head += n;
26688447a05SGarrett D'Amore sp->s_hidx += n;
26788447a05SGarrett D'Amore if (sp->s_hidx >= sp->s_nframes) {
26888447a05SGarrett D'Amore sp->s_hidx -= sp->s_nframes;
26988447a05SGarrett D'Amore }
27088447a05SGarrett D'Amore
27188447a05SGarrett D'Amore ASSERT(sp->s_tail <= sp->s_head);
27288447a05SGarrett D'Amore ASSERT(sp->s_hidx < sp->s_nframes);
27388447a05SGarrett D'Amore
27488447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
27588447a05SGarrett D'Amore
27688447a05SGarrett D'Amore return (n);
27788447a05SGarrett D'Amore }
27888447a05SGarrett D'Amore
27968c47f65SGarrett D'Amore uint_t
auclnt_produce_data(audio_stream_t * sp,caddr_t src,uint_t n)28068c47f65SGarrett D'Amore auclnt_produce_data(audio_stream_t *sp, caddr_t src, uint_t n)
28188447a05SGarrett D'Amore {
28268c47f65SGarrett D'Amore uint_t nframes;
28368c47f65SGarrett D'Amore uint_t framesz;
28468c47f65SGarrett D'Amore uint_t cnt;
28588447a05SGarrett D'Amore caddr_t data;
28688447a05SGarrett D'Amore
28788447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
28888447a05SGarrett D'Amore
28988447a05SGarrett D'Amore nframes = sp->s_nframes;
29088447a05SGarrett D'Amore framesz = sp->s_framesz;
29188447a05SGarrett D'Amore
29288447a05SGarrett D'Amore ASSERT(sp == &sp->s_client->c_ostream);
29388447a05SGarrett D'Amore ASSERT(sp->s_head >= sp->s_tail);
29488447a05SGarrett D'Amore ASSERT(sp->s_tidx < nframes);
29588447a05SGarrett D'Amore ASSERT(sp->s_hidx < nframes);
29688447a05SGarrett D'Amore
29788447a05SGarrett D'Amore cnt = n = min(n, nframes - (sp->s_head - sp->s_tail));
29888447a05SGarrett D'Amore data = sp->s_data + (sp->s_hidx * framesz);
29988447a05SGarrett D'Amore do {
30068c47f65SGarrett D'Amore uint_t nf, nb;
30188447a05SGarrett D'Amore
30288447a05SGarrett D'Amore nf = min(nframes - sp->s_hidx, n);
30388447a05SGarrett D'Amore nb = nf * framesz;
30488447a05SGarrett D'Amore
30588447a05SGarrett D'Amore bcopy(src, data, nb);
30688447a05SGarrett D'Amore
30788447a05SGarrett D'Amore src += nb;
30888447a05SGarrett D'Amore data += nb;
30988447a05SGarrett D'Amore
31088447a05SGarrett D'Amore n -= nf;
31188447a05SGarrett D'Amore sp->s_head += nf;
31288447a05SGarrett D'Amore sp->s_hidx += nf;
31388447a05SGarrett D'Amore if (sp->s_hidx == nframes) {
31488447a05SGarrett D'Amore sp->s_hidx = 0;
31588447a05SGarrett D'Amore data = sp->s_data;
31688447a05SGarrett D'Amore }
31788447a05SGarrett D'Amore } while (n);
31888447a05SGarrett D'Amore
31988447a05SGarrett D'Amore ASSERT(sp->s_tail <= sp->s_head);
32088447a05SGarrett D'Amore ASSERT(sp->s_hidx < nframes);
32188447a05SGarrett D'Amore
32288447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
32388447a05SGarrett D'Amore
32488447a05SGarrett D'Amore return (cnt);
32588447a05SGarrett D'Amore }
32688447a05SGarrett D'Amore
32788447a05SGarrett D'Amore int
auclnt_read(audio_client_t * c,struct uio * uio)32888447a05SGarrett D'Amore auclnt_read(audio_client_t *c, struct uio *uio)
32988447a05SGarrett D'Amore {
33088447a05SGarrett D'Amore audio_stream_t *sp = &c->c_istream;
33168c47f65SGarrett D'Amore uint_t cnt;
33288447a05SGarrett D'Amore int rv = 0;
33388447a05SGarrett D'Amore offset_t loff;
33488447a05SGarrett D'Amore int eagain;
33568c47f65SGarrett D'Amore uint_t tidx;
33668c47f65SGarrett D'Amore uint_t framesz;
33788447a05SGarrett D'Amore
33888447a05SGarrett D'Amore loff = uio->uio_loffset;
33988447a05SGarrett D'Amore eagain = EAGAIN;
34088447a05SGarrett D'Amore
34188447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
34288447a05SGarrett D'Amore
34388447a05SGarrett D'Amore if ((!sp->s_paused) && (!sp->s_running)) {
34488447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
34588447a05SGarrett D'Amore auclnt_start(sp);
34688447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
34788447a05SGarrett D'Amore }
34888447a05SGarrett D'Amore
34968c47f65SGarrett D'Amore
35068c47f65SGarrett D'Amore framesz = sp->s_framesz;
35168c47f65SGarrett D'Amore
35288447a05SGarrett D'Amore ASSERT(sp->s_head >= sp->s_tail);
35388447a05SGarrett D'Amore ASSERT(sp->s_tidx < sp->s_nframes);
35488447a05SGarrett D'Amore
35568c47f65SGarrett D'Amore while (uio->uio_resid >= framesz) {
35688447a05SGarrett D'Amore
35788447a05SGarrett D'Amore while ((cnt = (sp->s_head - sp->s_tail)) == 0) {
35888447a05SGarrett D'Amore if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
35988447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
36088447a05SGarrett D'Amore return (eagain);
36188447a05SGarrett D'Amore }
36288447a05SGarrett D'Amore if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
36388447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
36488447a05SGarrett D'Amore return (EINTR);
36588447a05SGarrett D'Amore }
36688447a05SGarrett D'Amore }
36788447a05SGarrett D'Amore
36868c47f65SGarrett D'Amore tidx = sp->s_tidx;
36968c47f65SGarrett D'Amore cnt = min(cnt, sp->s_nframes - tidx);
37068c47f65SGarrett D'Amore cnt = min(cnt, (uio->uio_resid / framesz));
37168c47f65SGarrett D'Amore
37268c47f65SGarrett D'Amore mutex_exit(&sp->s_lock);
37368c47f65SGarrett D'Amore rv = uiomove(sp->s_data + (tidx * framesz),
37468c47f65SGarrett D'Amore cnt * framesz, UIO_READ, uio);
37588447a05SGarrett D'Amore
37688447a05SGarrett D'Amore uio->uio_loffset = loff;
37788447a05SGarrett D'Amore eagain = 0;
37888447a05SGarrett D'Amore
37988447a05SGarrett D'Amore if (rv != 0) {
38088447a05SGarrett D'Amore return (rv);
38188447a05SGarrett D'Amore }
38288447a05SGarrett D'Amore
38368c47f65SGarrett D'Amore mutex_enter(&sp->s_lock);
38488447a05SGarrett D'Amore sp->s_tail += cnt;
38588447a05SGarrett D'Amore sp->s_tidx += cnt;
38688447a05SGarrett D'Amore if (sp->s_tidx == sp->s_nframes) {
38788447a05SGarrett D'Amore sp->s_tidx = 0;
38888447a05SGarrett D'Amore }
38988447a05SGarrett D'Amore }
39088447a05SGarrett D'Amore
39188447a05SGarrett D'Amore ASSERT(sp->s_tail <= sp->s_head);
39288447a05SGarrett D'Amore ASSERT(sp->s_tidx < sp->s_nframes);
39388447a05SGarrett D'Amore
39488447a05SGarrett D'Amore /* round off any remaining partial bits */
39588447a05SGarrett D'Amore uio->uio_resid = 0;
39688447a05SGarrett D'Amore
39788447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
39888447a05SGarrett D'Amore
39988447a05SGarrett D'Amore return (rv);
40088447a05SGarrett D'Amore }
40188447a05SGarrett D'Amore
40288447a05SGarrett D'Amore int
auclnt_write(audio_client_t * c,struct uio * uio)40388447a05SGarrett D'Amore auclnt_write(audio_client_t *c, struct uio *uio)
40488447a05SGarrett D'Amore {
40588447a05SGarrett D'Amore audio_stream_t *sp = &c->c_ostream;
40668c47f65SGarrett D'Amore uint_t cnt;
40788447a05SGarrett D'Amore int rv = 0;
40888447a05SGarrett D'Amore offset_t loff;
40988447a05SGarrett D'Amore int eagain;
41068c47f65SGarrett D'Amore uint_t framesz;
41168c47f65SGarrett D'Amore uint_t hidx;
41288447a05SGarrett D'Amore
41388447a05SGarrett D'Amore loff = uio->uio_loffset;
41488447a05SGarrett D'Amore eagain = EAGAIN;
41588447a05SGarrett D'Amore
41688447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
41788447a05SGarrett D'Amore
41868c47f65SGarrett D'Amore framesz = sp->s_framesz;
41968c47f65SGarrett D'Amore
42088447a05SGarrett D'Amore ASSERT(sp->s_head >= sp->s_tail);
42188447a05SGarrett D'Amore ASSERT(sp->s_hidx < sp->s_nframes);
42288447a05SGarrett D'Amore
42368c47f65SGarrett D'Amore while (uio->uio_resid >= framesz) {
42488447a05SGarrett D'Amore
42588447a05SGarrett D'Amore while ((cnt = sp->s_nframes - (sp->s_head - sp->s_tail)) == 0) {
42688447a05SGarrett D'Amore if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
42788447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
42888447a05SGarrett D'Amore return (eagain);
42988447a05SGarrett D'Amore }
43088447a05SGarrett D'Amore if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
43188447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
43288447a05SGarrett D'Amore return (EINTR);
43388447a05SGarrett D'Amore }
43488447a05SGarrett D'Amore }
43588447a05SGarrett D'Amore
43668c47f65SGarrett D'Amore hidx = sp->s_hidx;
43768c47f65SGarrett D'Amore cnt = min(cnt, sp->s_nframes - hidx);
43868c47f65SGarrett D'Amore cnt = min(cnt, (uio->uio_resid / framesz));
43968c47f65SGarrett D'Amore
44068c47f65SGarrett D'Amore /*
44168c47f65SGarrett D'Amore * We have to drop the stream lock, because the
44268c47f65SGarrett D'Amore * uiomove might require doing a page in, which could
44368c47f65SGarrett D'Amore * get blocked behind the PIL of the audio processing
44468c47f65SGarrett D'Amore * thread which also grabs the s_lock. (Hence, there
44568c47f65SGarrett D'Amore * is a risk of deadlock due to priority inversion.)
44668c47f65SGarrett D'Amore */
44768c47f65SGarrett D'Amore mutex_exit(&sp->s_lock);
44868c47f65SGarrett D'Amore
44968c47f65SGarrett D'Amore rv = uiomove(sp->s_data + (hidx * framesz),
45068c47f65SGarrett D'Amore cnt * framesz, UIO_WRITE, uio);
45188447a05SGarrett D'Amore
45288447a05SGarrett D'Amore uio->uio_loffset = loff;
45388447a05SGarrett D'Amore eagain = 0;
45488447a05SGarrett D'Amore
45588447a05SGarrett D'Amore if (rv != 0) {
45688447a05SGarrett D'Amore return (rv);
45788447a05SGarrett D'Amore }
45888447a05SGarrett D'Amore
45968c47f65SGarrett D'Amore mutex_enter(&sp->s_lock);
46068c47f65SGarrett D'Amore
46188447a05SGarrett D'Amore sp->s_head += cnt;
46288447a05SGarrett D'Amore sp->s_hidx += cnt;
46388447a05SGarrett D'Amore if (sp->s_hidx == sp->s_nframes) {
46488447a05SGarrett D'Amore sp->s_hidx = 0;
46588447a05SGarrett D'Amore }
46688447a05SGarrett D'Amore
46788447a05SGarrett D'Amore if ((!sp->s_paused) && (!sp->s_running) &&
46888447a05SGarrett D'Amore ((sp->s_head - sp->s_tail) > sp->s_fragfr)) {
46988447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
47088447a05SGarrett D'Amore auclnt_start(sp);
47188447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
47288447a05SGarrett D'Amore }
47388447a05SGarrett D'Amore }
47488447a05SGarrett D'Amore
47588447a05SGarrett D'Amore ASSERT(sp->s_tail <= sp->s_head);
47688447a05SGarrett D'Amore ASSERT(sp->s_hidx < sp->s_nframes);
47788447a05SGarrett D'Amore
47888447a05SGarrett D'Amore /* round off any remaining partial bits */
47988447a05SGarrett D'Amore uio->uio_resid = 0;
48088447a05SGarrett D'Amore
48188447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
48288447a05SGarrett D'Amore
48388447a05SGarrett D'Amore return (rv);
48488447a05SGarrett D'Amore }
48588447a05SGarrett D'Amore
48688447a05SGarrett D'Amore int
auclnt_chpoll(audio_client_t * c,short events,int anyyet,short * reventsp,struct pollhead ** phpp)48788447a05SGarrett D'Amore auclnt_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp,
48888447a05SGarrett D'Amore struct pollhead **phpp)
48988447a05SGarrett D'Amore {
49088447a05SGarrett D'Amore audio_stream_t *sp;
49188447a05SGarrett D'Amore short nev = 0;
49288447a05SGarrett D'Amore
49388447a05SGarrett D'Amore if (events & (POLLIN | POLLRDNORM)) {
49488447a05SGarrett D'Amore sp = &c->c_istream;
49588447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
49688447a05SGarrett D'Amore if ((sp->s_head - sp->s_tail) > sp->s_fragfr) {
49788447a05SGarrett D'Amore nev = POLLIN | POLLRDNORM;
49888447a05SGarrett D'Amore }
49988447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
50088447a05SGarrett D'Amore }
50188447a05SGarrett D'Amore
50288447a05SGarrett D'Amore if (events & POLLOUT) {
50388447a05SGarrett D'Amore sp = &c->c_ostream;
50488447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
50588447a05SGarrett D'Amore if ((sp->s_nframes - (sp->s_head - sp->s_tail)) >
50688447a05SGarrett D'Amore sp->s_fragfr) {
50788447a05SGarrett D'Amore nev = POLLOUT;
50888447a05SGarrett D'Amore }
50988447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
51088447a05SGarrett D'Amore }
51188447a05SGarrett D'Amore
51288447a05SGarrett D'Amore if (nev) {
51388447a05SGarrett D'Amore *reventsp = nev & events;
51488447a05SGarrett D'Amore } else {
51588447a05SGarrett D'Amore *reventsp = 0;
51688447a05SGarrett D'Amore if (!anyyet) {
51788447a05SGarrett D'Amore *phpp = &c->c_pollhead;
51888447a05SGarrett D'Amore }
51988447a05SGarrett D'Amore }
52088447a05SGarrett D'Amore return (0);
52188447a05SGarrett D'Amore }
52288447a05SGarrett D'Amore
52388447a05SGarrett D'Amore void
auclnt_pollwakeup(audio_client_t * c,short events)52488447a05SGarrett D'Amore auclnt_pollwakeup(audio_client_t *c, short events)
52588447a05SGarrett D'Amore {
52688447a05SGarrett D'Amore pollwakeup(&c->c_pollhead, events);
52788447a05SGarrett D'Amore }
52888447a05SGarrett D'Amore
52988447a05SGarrett D'Amore void
auclnt_get_output_qlen(audio_client_t * c,uint_t * slen,uint_t * flen)53068c47f65SGarrett D'Amore auclnt_get_output_qlen(audio_client_t *c, uint_t *slen, uint_t *flen)
53188447a05SGarrett D'Amore {
53288447a05SGarrett D'Amore audio_stream_t *sp = &c->c_ostream;
53388447a05SGarrett D'Amore audio_engine_t *e = sp->s_engine;
53488447a05SGarrett D'Amore uint64_t el, sl;
53568c47f65SGarrett D'Amore uint_t cnt, er, sr;
53688447a05SGarrett D'Amore
53788447a05SGarrett D'Amore if (e == NULL) {
53888447a05SGarrett D'Amore /* if no output engine, can't do it! */
53988447a05SGarrett D'Amore *slen = 0;
54088447a05SGarrett D'Amore *flen = 0;
54188447a05SGarrett D'Amore return;
54288447a05SGarrett D'Amore }
54388447a05SGarrett D'Amore
54488447a05SGarrett D'Amore mutex_enter(&e->e_lock);
54588447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
546f9ead4a5SGarrett D'Amore if (e->e_ops.audio_engine_qlen != NULL) {
547f9ead4a5SGarrett D'Amore el = ENG_QLEN(e) + (e->e_head - e->e_tail);
548f9ead4a5SGarrett D'Amore } else {
549f9ead4a5SGarrett D'Amore el = (e->e_head - e->e_tail);
550f9ead4a5SGarrett D'Amore }
55188447a05SGarrett D'Amore er = e->e_rate;
55288447a05SGarrett D'Amore sl = sp->s_cnv_cnt;
55388447a05SGarrett D'Amore sr = sp->s_user_parms->p_rate;
55468c47f65SGarrett D'Amore cnt = (uint_t)(sp->s_head - sp->s_tail);
55588447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
55688447a05SGarrett D'Amore mutex_exit(&e->e_lock);
55788447a05SGarrett D'Amore
55888447a05SGarrett D'Amore /* engine frames converted to stream rate, plus stream frames */
55988447a05SGarrett D'Amore *slen = cnt;
56068c47f65SGarrett D'Amore *flen = ((uint_t)(((el * sr) / er) + sl));
56188447a05SGarrett D'Amore }
56288447a05SGarrett D'Amore
56388447a05SGarrett D'Amore int
auclnt_set_format(audio_stream_t * sp,int fmt)56488447a05SGarrett D'Amore auclnt_set_format(audio_stream_t *sp, int fmt)
56588447a05SGarrett D'Amore {
56688447a05SGarrett D'Amore audio_parms_t parms;
56788447a05SGarrett D'Amore int rv = 0;
56888447a05SGarrett D'Amore
56988447a05SGarrett D'Amore /*
57088447a05SGarrett D'Amore * AC3: If we select an AC3 format, then we have to allocate
57188447a05SGarrett D'Amore * another engine. Normally this will be an output only
57288447a05SGarrett D'Amore * engine. However, for now we aren't supporting AC3
57388447a05SGarrett D'Amore * passthru.
57488447a05SGarrett D'Amore */
57588447a05SGarrett D'Amore
57688447a05SGarrett D'Amore switch (fmt) {
57788447a05SGarrett D'Amore case AUDIO_FORMAT_U8:
57888447a05SGarrett D'Amore case AUDIO_FORMAT_ULAW:
57988447a05SGarrett D'Amore case AUDIO_FORMAT_ALAW:
58088447a05SGarrett D'Amore case AUDIO_FORMAT_S8:
58188447a05SGarrett D'Amore case AUDIO_FORMAT_S16_LE:
58288447a05SGarrett D'Amore case AUDIO_FORMAT_S16_BE:
58388447a05SGarrett D'Amore case AUDIO_FORMAT_U16_LE:
58488447a05SGarrett D'Amore case AUDIO_FORMAT_U16_BE:
58588447a05SGarrett D'Amore case AUDIO_FORMAT_S24_LE:
58688447a05SGarrett D'Amore case AUDIO_FORMAT_S24_BE:
58788447a05SGarrett D'Amore case AUDIO_FORMAT_S32_LE:
58888447a05SGarrett D'Amore case AUDIO_FORMAT_S32_BE:
58988447a05SGarrett D'Amore case AUDIO_FORMAT_S24_PACKED:
59088447a05SGarrett D'Amore break;
59188447a05SGarrett D'Amore
59288447a05SGarrett D'Amore case AUDIO_FORMAT_AC3: /* AC3: PASSTHRU */
59388447a05SGarrett D'Amore default:
59488447a05SGarrett D'Amore return (ENOTSUP);
59588447a05SGarrett D'Amore }
59688447a05SGarrett D'Amore
59788447a05SGarrett D'Amore
59888447a05SGarrett D'Amore /*
59988447a05SGarrett D'Amore * Optimization. Some personalities send us the same format
60088447a05SGarrett D'Amore * over and over again. (Sun personality does this
60188447a05SGarrett D'Amore * repeatedly.) setup_src is potentially expensive, so we
60288447a05SGarrett D'Amore * avoid doing it unless we really need to.
60388447a05SGarrett D'Amore */
6042c30fa45SGarrett D'Amore if (fmt != sp->s_user_parms->p_format) {
60588447a05SGarrett D'Amore /*
60688447a05SGarrett D'Amore * Note that setting the format doesn't check that the
60788447a05SGarrett D'Amore * audio streams have been paused. As a result, any
60888447a05SGarrett D'Amore * data still playing or recording will probably get
60988447a05SGarrett D'Amore * misinterpreted. It would be smart if the client
61088447a05SGarrett D'Amore * application paused/stopped playback before changing
61188447a05SGarrett D'Amore * formats.
61288447a05SGarrett D'Amore */
61388447a05SGarrett D'Amore parms.p_format = fmt;
6142c30fa45SGarrett D'Amore rv = auimpl_engine_setup(sp, 0, &parms, FORMAT_MSK_FMT);
61588447a05SGarrett D'Amore }
61688447a05SGarrett D'Amore
61788447a05SGarrett D'Amore return (rv);
61888447a05SGarrett D'Amore }
61988447a05SGarrett D'Amore
62088447a05SGarrett D'Amore int
auclnt_get_format(audio_stream_t * sp)62188447a05SGarrett D'Amore auclnt_get_format(audio_stream_t *sp)
62288447a05SGarrett D'Amore {
62388447a05SGarrett D'Amore return (sp->s_user_parms->p_format);
62488447a05SGarrett D'Amore }
62588447a05SGarrett D'Amore
62688447a05SGarrett D'Amore int
auclnt_get_output_format(audio_client_t * c)62788447a05SGarrett D'Amore auclnt_get_output_format(audio_client_t *c)
62888447a05SGarrett D'Amore {
62988447a05SGarrett D'Amore return (c->c_ostream.s_user_parms->p_format);
63088447a05SGarrett D'Amore }
63188447a05SGarrett D'Amore
63288447a05SGarrett D'Amore int
auclnt_get_input_format(audio_client_t * c)63388447a05SGarrett D'Amore auclnt_get_input_format(audio_client_t *c)
63488447a05SGarrett D'Amore {
63588447a05SGarrett D'Amore return (c->c_istream.s_user_parms->p_format);
63688447a05SGarrett D'Amore }
63788447a05SGarrett D'Amore
63888447a05SGarrett D'Amore int
auclnt_set_channels(audio_stream_t * sp,int nchan)63988447a05SGarrett D'Amore auclnt_set_channels(audio_stream_t *sp, int nchan)
64088447a05SGarrett D'Amore {
64188447a05SGarrett D'Amore audio_parms_t parms;
64288447a05SGarrett D'Amore int rv = 0;
64388447a05SGarrett D'Amore
64488447a05SGarrett D'Amore /* Validate setting */
64588447a05SGarrett D'Amore if ((nchan > AUDIO_MAX_CHANNELS) || (nchan < 1)) {
64688447a05SGarrett D'Amore return (EINVAL);
64788447a05SGarrett D'Amore }
64888447a05SGarrett D'Amore
6492c30fa45SGarrett D'Amore if (nchan != sp->s_user_parms->p_nchan) {
65088447a05SGarrett D'Amore parms.p_nchan = nchan;
6512c30fa45SGarrett D'Amore rv = auimpl_engine_setup(sp, 0, &parms, FORMAT_MSK_CHAN);
65288447a05SGarrett D'Amore }
65388447a05SGarrett D'Amore
65488447a05SGarrett D'Amore return (rv);
65588447a05SGarrett D'Amore }
65688447a05SGarrett D'Amore
65788447a05SGarrett D'Amore int
auclnt_get_channels(audio_stream_t * sp)65888447a05SGarrett D'Amore auclnt_get_channels(audio_stream_t *sp)
65988447a05SGarrett D'Amore {
66088447a05SGarrett D'Amore return (sp->s_user_parms->p_nchan);
66188447a05SGarrett D'Amore }
66288447a05SGarrett D'Amore
66353a539a7SGarrett D'Amore
66453a539a7SGarrett D'Amore static void
auimpl_set_gain_master(audio_stream_t * sp,uint8_t gain)66588447a05SGarrett D'Amore auimpl_set_gain_master(audio_stream_t *sp, uint8_t gain)
66688447a05SGarrett D'Amore {
66788447a05SGarrett D'Amore uint32_t scaled;
66888447a05SGarrett D'Amore
66988447a05SGarrett D'Amore if (gain > 100) {
67088447a05SGarrett D'Amore gain = 0;
67188447a05SGarrett D'Amore }
67288447a05SGarrett D'Amore
67388447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
67488447a05SGarrett D'Amore if (sp->s_gain_master == gain) {
67588447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
67688447a05SGarrett D'Amore return;
67788447a05SGarrett D'Amore }
67888447a05SGarrett D'Amore
67988447a05SGarrett D'Amore /*
68088447a05SGarrett D'Amore * calculate the scaled values. Done now to avoid calculations
68188447a05SGarrett D'Amore * later.
68288447a05SGarrett D'Amore */
68388447a05SGarrett D'Amore scaled = (gain * sp->s_gain_pct * AUDIO_DB_SIZE) / (100 * 100);
68488447a05SGarrett D'Amore
68588447a05SGarrett D'Amore sp->s_gain_master = gain;
68688447a05SGarrett D'Amore sp->s_gain_scaled = auimpl_db_table[scaled];
68788447a05SGarrett D'Amore
68888447a05SGarrett D'Amore if (!sp->s_muted) {
68988447a05SGarrett D'Amore sp->s_gain_eff = sp->s_gain_scaled;
69088447a05SGarrett D'Amore }
69188447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
69288447a05SGarrett D'Amore }
69388447a05SGarrett D'Amore
69453a539a7SGarrett D'Amore int
auimpl_set_pcmvol(void * arg,uint64_t val)69553a539a7SGarrett D'Amore auimpl_set_pcmvol(void *arg, uint64_t val)
69653a539a7SGarrett D'Amore {
69753a539a7SGarrett D'Amore audio_dev_t *d = arg;
69853a539a7SGarrett D'Amore list_t *l = &d->d_clients;
69953a539a7SGarrett D'Amore audio_client_t *c;
70053a539a7SGarrett D'Amore
70153a539a7SGarrett D'Amore if (val > 100) {
70253a539a7SGarrett D'Amore return (EINVAL);
70353a539a7SGarrett D'Amore }
70453a539a7SGarrett D'Amore rw_enter(&auimpl_client_lock, RW_WRITER);
70553a539a7SGarrett D'Amore d->d_pcmvol = val & 0xff;
70653a539a7SGarrett D'Amore rw_downgrade(&auimpl_client_lock);
70753a539a7SGarrett D'Amore
70853a539a7SGarrett D'Amore for (c = list_head(l); c; c = list_next(l, c)) {
70953a539a7SGarrett D'Amore /* don't need to check is_active here, its safe */
71053a539a7SGarrett D'Amore auimpl_set_gain_master(&c->c_ostream, (uint8_t)val);
71153a539a7SGarrett D'Amore }
71253a539a7SGarrett D'Amore rw_exit(&auimpl_client_lock);
71353a539a7SGarrett D'Amore
71453a539a7SGarrett D'Amore return (0);
71553a539a7SGarrett D'Amore }
71653a539a7SGarrett D'Amore
71753a539a7SGarrett D'Amore int
auimpl_get_pcmvol(void * arg,uint64_t * val)71853a539a7SGarrett D'Amore auimpl_get_pcmvol(void *arg, uint64_t *val)
71953a539a7SGarrett D'Amore {
72053a539a7SGarrett D'Amore audio_dev_t *d = arg;
72153a539a7SGarrett D'Amore
72253a539a7SGarrett D'Amore *val = d->d_pcmvol;
72353a539a7SGarrett D'Amore return (0);
72453a539a7SGarrett D'Amore }
72553a539a7SGarrett D'Amore
72688447a05SGarrett D'Amore void
auclnt_set_gain(audio_stream_t * sp,uint8_t gain)72788447a05SGarrett D'Amore auclnt_set_gain(audio_stream_t *sp, uint8_t gain)
72888447a05SGarrett D'Amore {
72988447a05SGarrett D'Amore uint32_t scaled;
73088447a05SGarrett D'Amore
73188447a05SGarrett D'Amore if (gain > 100) {
73288447a05SGarrett D'Amore gain = 0;
73388447a05SGarrett D'Amore }
73488447a05SGarrett D'Amore
73588447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
73688447a05SGarrett D'Amore
73788447a05SGarrett D'Amore /* if no change, don't bother doing updates */
73888447a05SGarrett D'Amore if (sp->s_gain_pct == gain) {
73988447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
74088447a05SGarrett D'Amore return;
74188447a05SGarrett D'Amore }
74288447a05SGarrett D'Amore
74388447a05SGarrett D'Amore /*
74488447a05SGarrett D'Amore * calculate the scaled values. Done now to avoid calculations
74588447a05SGarrett D'Amore * later.
74688447a05SGarrett D'Amore */
74788447a05SGarrett D'Amore scaled = (gain * sp->s_gain_master * AUDIO_DB_SIZE) / (100 * 100);
74888447a05SGarrett D'Amore
74988447a05SGarrett D'Amore sp->s_gain_pct = gain;
75088447a05SGarrett D'Amore sp->s_gain_scaled = auimpl_db_table[scaled];
75188447a05SGarrett D'Amore
75288447a05SGarrett D'Amore if (!sp->s_muted) {
75388447a05SGarrett D'Amore sp->s_gain_eff = sp->s_gain_scaled;
75488447a05SGarrett D'Amore }
75588447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
75688447a05SGarrett D'Amore
757682cb104SGarrett D'Amore atomic_inc_uint(&sp->s_client->c_dev->d_serial);
75888447a05SGarrett D'Amore }
75988447a05SGarrett D'Amore
76088447a05SGarrett D'Amore uint8_t
auclnt_get_gain(audio_stream_t * sp)76188447a05SGarrett D'Amore auclnt_get_gain(audio_stream_t *sp)
76288447a05SGarrett D'Amore {
76388447a05SGarrett D'Amore return (sp->s_gain_pct);
76488447a05SGarrett D'Amore }
76588447a05SGarrett D'Amore
76688447a05SGarrett D'Amore void
auclnt_set_muted(audio_stream_t * sp,boolean_t muted)76788447a05SGarrett D'Amore auclnt_set_muted(audio_stream_t *sp, boolean_t muted)
76888447a05SGarrett D'Amore {
76988447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
77088447a05SGarrett D'Amore
77188447a05SGarrett D'Amore /* if no work change, don't bother doing updates */
77288447a05SGarrett D'Amore if (sp->s_muted == muted) {
77388447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
77488447a05SGarrett D'Amore return;
77588447a05SGarrett D'Amore }
77688447a05SGarrett D'Amore
77788447a05SGarrett D'Amore sp->s_muted = muted;
77888447a05SGarrett D'Amore if (muted) {
77988447a05SGarrett D'Amore sp->s_gain_eff = 0;
78088447a05SGarrett D'Amore } else {
78188447a05SGarrett D'Amore sp->s_gain_eff = sp->s_gain_scaled;
78288447a05SGarrett D'Amore }
78388447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
78488447a05SGarrett D'Amore
785682cb104SGarrett D'Amore atomic_inc_uint(&sp->s_client->c_dev->d_serial);
78688447a05SGarrett D'Amore }
78788447a05SGarrett D'Amore
78888447a05SGarrett D'Amore boolean_t
auclnt_get_muted(audio_stream_t * sp)78988447a05SGarrett D'Amore auclnt_get_muted(audio_stream_t *sp)
79088447a05SGarrett D'Amore {
79188447a05SGarrett D'Amore return (sp->s_muted);
79288447a05SGarrett D'Amore }
79388447a05SGarrett D'Amore
794622a30bfSGarrett D'Amore boolean_t
auclnt_is_running(audio_stream_t * sp)795622a30bfSGarrett D'Amore auclnt_is_running(audio_stream_t *sp)
796622a30bfSGarrett D'Amore {
797622a30bfSGarrett D'Amore return (sp->s_running);
798622a30bfSGarrett D'Amore }
799622a30bfSGarrett D'Amore
80088447a05SGarrett D'Amore void
auclnt_start(audio_stream_t * sp)80188447a05SGarrett D'Amore auclnt_start(audio_stream_t *sp)
80288447a05SGarrett D'Amore {
80388447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
80488447a05SGarrett D'Amore sp->s_running = B_TRUE;
80588447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
80688447a05SGarrett D'Amore }
80788447a05SGarrett D'Amore
80888447a05SGarrett D'Amore void
auclnt_stop(audio_stream_t * sp)80988447a05SGarrett D'Amore auclnt_stop(audio_stream_t *sp)
81088447a05SGarrett D'Amore {
81188447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
81288447a05SGarrett D'Amore /* if running, then stop it */
81388447a05SGarrett D'Amore if (sp->s_running) {
81488447a05SGarrett D'Amore sp->s_running = B_FALSE;
81588447a05SGarrett D'Amore /*
81688447a05SGarrett D'Amore * if we stopped the engine, we might need to wake up
81788447a05SGarrett D'Amore * a thread that is waiting for drain to complete.
81888447a05SGarrett D'Amore */
81988447a05SGarrett D'Amore cv_broadcast(&sp->s_cv);
82088447a05SGarrett D'Amore }
82188447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
82288447a05SGarrett D'Amore }
82388447a05SGarrett D'Amore
82488447a05SGarrett D'Amore /*
82588447a05SGarrett D'Amore * When pausing, no new data will be played after the most recently
82688447a05SGarrett D'Amore * mixed samples have played. However, the audio engine will continue
82788447a05SGarrett D'Amore * to play (possibly just silence).
82888447a05SGarrett D'Amore *
82988447a05SGarrett D'Amore * Note that we don't reference count the device, or release/close the
83088447a05SGarrett D'Amore * engine here. Once fired up, the engine continues running unil it
83188447a05SGarrett D'Amore * is closed.
83288447a05SGarrett D'Amore */
83388447a05SGarrett D'Amore void
auclnt_set_paused(audio_stream_t * sp)83488447a05SGarrett D'Amore auclnt_set_paused(audio_stream_t *sp)
83588447a05SGarrett D'Amore {
83688447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
83788447a05SGarrett D'Amore if (sp->s_paused) {
83888447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
83988447a05SGarrett D'Amore return;
84088447a05SGarrett D'Amore }
84188447a05SGarrett D'Amore sp->s_paused = B_TRUE;
84288447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
84388447a05SGarrett D'Amore
84488447a05SGarrett D'Amore auclnt_stop(sp);
84588447a05SGarrett D'Amore
846682cb104SGarrett D'Amore atomic_inc_uint(&sp->s_client->c_dev->d_serial);
84788447a05SGarrett D'Amore }
84888447a05SGarrett D'Amore
84988447a05SGarrett D'Amore void
auclnt_clear_paused(audio_stream_t * sp)85088447a05SGarrett D'Amore auclnt_clear_paused(audio_stream_t *sp)
85188447a05SGarrett D'Amore {
85288447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
85388447a05SGarrett D'Amore if (!sp->s_paused) {
85488447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
85588447a05SGarrett D'Amore return;
85688447a05SGarrett D'Amore }
85788447a05SGarrett D'Amore sp->s_paused = B_FALSE;
85888447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
85988447a05SGarrett D'Amore }
86088447a05SGarrett D'Amore
86188447a05SGarrett D'Amore boolean_t
auclnt_is_paused(audio_stream_t * sp)86288447a05SGarrett D'Amore auclnt_is_paused(audio_stream_t *sp)
86388447a05SGarrett D'Amore {
86488447a05SGarrett D'Amore return (sp->s_paused);
86588447a05SGarrett D'Amore }
86688447a05SGarrett D'Amore
86788447a05SGarrett D'Amore void
auclnt_flush(audio_stream_t * sp)86888447a05SGarrett D'Amore auclnt_flush(audio_stream_t *sp)
86988447a05SGarrett D'Amore {
87088447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
87188447a05SGarrett D'Amore if (sp == &sp->s_client->c_ostream) {
87288447a05SGarrett D'Amore sp->s_tail = sp->s_head;
87388447a05SGarrett D'Amore sp->s_tidx = sp->s_hidx;
87488447a05SGarrett D'Amore } else {
87588447a05SGarrett D'Amore sp->s_head = sp->s_tail;
87688447a05SGarrett D'Amore sp->s_hidx = sp->s_tidx;
87788447a05SGarrett D'Amore }
87888447a05SGarrett D'Amore sp->s_cnv_cnt = 0;
87988447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
88088447a05SGarrett D'Amore }
88188447a05SGarrett D'Amore
88288447a05SGarrett D'Amore int
auclnt_get_oflag(audio_client_t * c)88388447a05SGarrett D'Amore auclnt_get_oflag(audio_client_t *c)
88488447a05SGarrett D'Amore {
88588447a05SGarrett D'Amore return (c->c_omode);
88688447a05SGarrett D'Amore }
88788447a05SGarrett D'Amore
88888447a05SGarrett D'Amore /*
88988447a05SGarrett D'Amore * These routines should not be accessed by client "personality"
89088447a05SGarrett D'Amore * implementations, but are for private framework use only.
89188447a05SGarrett D'Amore */
89288447a05SGarrett D'Amore
89388447a05SGarrett D'Amore void
auimpl_client_init(void)89488447a05SGarrett D'Amore auimpl_client_init(void)
89588447a05SGarrett D'Amore {
89688447a05SGarrett D'Amore rw_init(&auimpl_client_lock, NULL, RW_DRIVER, NULL);
89788447a05SGarrett D'Amore list_create(&auimpl_clients, sizeof (struct audio_client),
89888447a05SGarrett D'Amore offsetof(struct audio_client, c_global_linkage));
89988447a05SGarrett D'Amore }
90088447a05SGarrett D'Amore
90188447a05SGarrett D'Amore void
auimpl_client_fini(void)90288447a05SGarrett D'Amore auimpl_client_fini(void)
90388447a05SGarrett D'Amore {
90488447a05SGarrett D'Amore rw_destroy(&auimpl_client_lock);
90588447a05SGarrett D'Amore list_destroy(&auimpl_clients);
90688447a05SGarrett D'Amore }
90788447a05SGarrett D'Amore
90888447a05SGarrett D'Amore static int
auimpl_stream_init(audio_stream_t * sp,audio_client_t * c)90988447a05SGarrett D'Amore auimpl_stream_init(audio_stream_t *sp, audio_client_t *c)
91088447a05SGarrett D'Amore {
91188447a05SGarrett D'Amore mutex_init(&sp->s_lock, NULL, MUTEX_DRIVER, NULL);
91288447a05SGarrett D'Amore cv_init(&sp->s_cv, NULL, CV_DRIVER, NULL);
91388447a05SGarrett D'Amore sp->s_client = c;
91488447a05SGarrett D'Amore
91588447a05SGarrett D'Amore if (sp == &c->c_ostream) {
91688447a05SGarrett D'Amore sp->s_user_parms = &sp->s_cnv_src_parms;
91788447a05SGarrett D'Amore sp->s_phys_parms = &sp->s_cnv_dst_parms;
91888447a05SGarrett D'Amore sp->s_engcap = ENGINE_OUTPUT_CAP;
91988447a05SGarrett D'Amore } else {
92088447a05SGarrett D'Amore ASSERT(sp == &c->c_istream);
92188447a05SGarrett D'Amore sp->s_user_parms = &sp->s_cnv_dst_parms;
92288447a05SGarrett D'Amore sp->s_phys_parms = &sp->s_cnv_src_parms;
92388447a05SGarrett D'Amore sp->s_engcap = ENGINE_INPUT_CAP;
92488447a05SGarrett D'Amore }
92588447a05SGarrett D'Amore
92688447a05SGarrett D'Amore /* for now initialize conversion parameters */
92788447a05SGarrett D'Amore sp->s_src_quality = 3; /* reasonable compromise for now */
92888447a05SGarrett D'Amore sp->s_cnv_dst_nchan = 2;
92988447a05SGarrett D'Amore sp->s_cnv_dst_format = AUDIO_FORMAT_S24_NE;
93088447a05SGarrett D'Amore sp->s_cnv_dst_rate = 48000;
93188447a05SGarrett D'Amore sp->s_cnv_src_nchan = 2;
93288447a05SGarrett D'Amore sp->s_cnv_src_format = AUDIO_FORMAT_S24_NE;
93388447a05SGarrett D'Amore sp->s_cnv_src_rate = 48000;
93488447a05SGarrett D'Amore
93588447a05SGarrett D'Amore /* set volume/gain all the way up */
93688447a05SGarrett D'Amore sp->s_muted = B_FALSE;
93788447a05SGarrett D'Amore sp->s_gain_pct = 0;
93888447a05SGarrett D'Amore sp->s_gain_scaled = AUDIO_VOL_SCALE;
93988447a05SGarrett D'Amore sp->s_gain_eff = AUDIO_VOL_SCALE;
94088447a05SGarrett D'Amore
94188447a05SGarrett D'Amore /*
94288447a05SGarrett D'Amore * We have to start off with a reasonable buffer and
94388447a05SGarrett D'Amore * interrupt configuration.
94488447a05SGarrett D'Amore */
94588447a05SGarrett D'Amore sp->s_allocsz = 65536;
94688447a05SGarrett D'Amore sp->s_data = ddi_umem_alloc(sp->s_allocsz, DDI_UMEM_NOSLEEP,
94788447a05SGarrett D'Amore &sp->s_cookie);
94888447a05SGarrett D'Amore if (sp->s_data == NULL) {
94988447a05SGarrett D'Amore sp->s_allocsz = 0;
95088447a05SGarrett D'Amore audio_dev_warn(c->c_dev, "ddi_umem_alloc failed");
95188447a05SGarrett D'Amore return (ENOMEM);
95288447a05SGarrett D'Amore }
95388447a05SGarrett D'Amore /* make sure no stale data left in stream */
95488447a05SGarrett D'Amore bzero(sp->s_data, sp->s_allocsz);
95588447a05SGarrett D'Amore
95688447a05SGarrett D'Amore /*
95788447a05SGarrett D'Amore * Allocate SRC and data conversion state.
95888447a05SGarrett D'Amore */
95988447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
96088447a05SGarrett D'Amore if (auimpl_format_alloc(sp) != 0) {
96188447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
96288447a05SGarrett D'Amore return (ENOMEM);
96388447a05SGarrett D'Amore }
96488447a05SGarrett D'Amore
96588447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
96688447a05SGarrett D'Amore
96788447a05SGarrett D'Amore return (0);
96888447a05SGarrett D'Amore }
96988447a05SGarrett D'Amore
97088447a05SGarrett D'Amore
97188447a05SGarrett D'Amore static void
audio_stream_fini(audio_stream_t * sp)97288447a05SGarrett D'Amore audio_stream_fini(audio_stream_t *sp)
97388447a05SGarrett D'Amore {
97488447a05SGarrett D'Amore auimpl_format_free(sp);
97588447a05SGarrett D'Amore if (sp->s_cnv_buf0)
97688447a05SGarrett D'Amore kmem_free(sp->s_cnv_buf0, sp->s_cnv_max);
97788447a05SGarrett D'Amore if (sp->s_cnv_buf1)
97888447a05SGarrett D'Amore kmem_free(sp->s_cnv_buf1, sp->s_cnv_max);
97988447a05SGarrett D'Amore mutex_destroy(&sp->s_lock);
98088447a05SGarrett D'Amore cv_destroy(&sp->s_cv);
98188447a05SGarrett D'Amore if (sp->s_data != NULL) {
98288447a05SGarrett D'Amore ddi_umem_free(sp->s_cookie);
98388447a05SGarrett D'Amore sp->s_data = NULL;
98488447a05SGarrett D'Amore }
98588447a05SGarrett D'Amore }
98688447a05SGarrett D'Amore
98788447a05SGarrett D'Amore int
auclnt_start_drain(audio_client_t * c)98888447a05SGarrett D'Amore auclnt_start_drain(audio_client_t *c)
98988447a05SGarrett D'Amore {
99088447a05SGarrett D'Amore audio_stream_t *sp;
99188447a05SGarrett D'Amore int rv;
99288447a05SGarrett D'Amore
99388447a05SGarrett D'Amore sp = &c->c_ostream;
99488447a05SGarrett D'Amore
99588447a05SGarrett D'Amore /* start an asynchronous drain operation. */
99688447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
99788447a05SGarrett D'Amore if (sp->s_paused || !sp->s_running) {
99888447a05SGarrett D'Amore rv = EALREADY;
99988447a05SGarrett D'Amore } else {
100088447a05SGarrett D'Amore sp->s_draining = B_TRUE;
100188447a05SGarrett D'Amore rv = 0;
100288447a05SGarrett D'Amore }
100388447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
100488447a05SGarrett D'Amore return (rv);
100588447a05SGarrett D'Amore }
100688447a05SGarrett D'Amore
100788447a05SGarrett D'Amore int
auclnt_drain(audio_client_t * c)100888447a05SGarrett D'Amore auclnt_drain(audio_client_t *c)
100988447a05SGarrett D'Amore {
101088447a05SGarrett D'Amore audio_stream_t *sp;
101188447a05SGarrett D'Amore
101288447a05SGarrett D'Amore sp = &c->c_ostream;
101388447a05SGarrett D'Amore
101488447a05SGarrett D'Amore /*
101588447a05SGarrett D'Amore * Note: Drain logic will automatically "stop" the stream when
101688447a05SGarrett D'Amore * the drain threshold has been reached. So all we have to do
101788447a05SGarrett D'Amore * is wait for the stream to stop.
101888447a05SGarrett D'Amore */
101988447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
102088447a05SGarrett D'Amore sp->s_draining = B_TRUE;
102188447a05SGarrett D'Amore while (sp->s_draining && sp->s_running && !sp->s_paused) {
102288447a05SGarrett D'Amore if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
102388447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
102488447a05SGarrett D'Amore return (EINTR);
102588447a05SGarrett D'Amore }
102688447a05SGarrett D'Amore }
102788447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
102888447a05SGarrett D'Amore return (0);
102988447a05SGarrett D'Amore }
103088447a05SGarrett D'Amore
103188447a05SGarrett D'Amore audio_client_t *
auimpl_client_create(dev_t dev)103288447a05SGarrett D'Amore auimpl_client_create(dev_t dev)
103388447a05SGarrett D'Amore {
103488447a05SGarrett D'Amore audio_client_ops_t *ops;
103588447a05SGarrett D'Amore audio_client_t *c;
103688447a05SGarrett D'Amore audio_client_t *next;
103788447a05SGarrett D'Amore list_t *list = &auimpl_clients;
103888447a05SGarrett D'Amore minor_t minor;
103988447a05SGarrett D'Amore audio_dev_t *d;
104088447a05SGarrett D'Amore
104188447a05SGarrett D'Amore /* validate minor number */
104288447a05SGarrett D'Amore minor = getminor(dev) & AUDIO_MN_TYPE_MASK;
104388447a05SGarrett D'Amore if ((ops = audio_client_ops[minor]) == NULL) {
104488447a05SGarrett D'Amore return (NULL);
104588447a05SGarrett D'Amore }
104688447a05SGarrett D'Amore
104788447a05SGarrett D'Amore /* lookup device instance */
104888447a05SGarrett D'Amore if ((d = auimpl_dev_hold_by_devt(dev)) == NULL) {
104988447a05SGarrett D'Amore audio_dev_warn(NULL, "no audio_dev for dev_t %d,%d",
105088447a05SGarrett D'Amore getmajor(dev), getminor(dev));
105188447a05SGarrett D'Amore return (NULL);
105288447a05SGarrett D'Amore }
105388447a05SGarrett D'Amore
105488447a05SGarrett D'Amore if ((c = kmem_zalloc(sizeof (*c), KM_NOSLEEP)) == NULL) {
105588447a05SGarrett D'Amore audio_dev_warn(d, "unable to allocate client structure");
105688447a05SGarrett D'Amore auimpl_dev_release(d);
105788447a05SGarrett D'Amore return (NULL);
105888447a05SGarrett D'Amore }
105988447a05SGarrett D'Amore c->c_dev = d;
106088447a05SGarrett D'Amore
106188447a05SGarrett D'Amore mutex_init(&c->c_lock, NULL, MUTEX_DRIVER, NULL);
106288447a05SGarrett D'Amore cv_init(&c->c_cv, NULL, CV_DRIVER, NULL);
106388447a05SGarrett D'Amore
106488447a05SGarrett D'Amore if ((auimpl_stream_init(&c->c_ostream, c) != 0) ||
106588447a05SGarrett D'Amore (auimpl_stream_init(&c->c_istream, c) != 0)) {
106688447a05SGarrett D'Amore goto failed;
106788447a05SGarrett D'Amore }
106888447a05SGarrett D'Amore
106988447a05SGarrett D'Amore c->c_major = getmajor(dev);
107088447a05SGarrett D'Amore c->c_origminor = getminor(dev);
107188447a05SGarrett D'Amore c->c_ops = *ops;
107288447a05SGarrett D'Amore
107388447a05SGarrett D'Amore /*
107488447a05SGarrett D'Amore * We hold the client lock here.
107588447a05SGarrett D'Amore */
107688447a05SGarrett D'Amore rw_enter(&auimpl_client_lock, RW_WRITER);
107788447a05SGarrett D'Amore
107888447a05SGarrett D'Amore minor = AUDIO_MN_CLONE_MASK;
107988447a05SGarrett D'Amore for (next = list_head(list); next; next = list_next(list, next)) {
108088447a05SGarrett D'Amore if (next->c_minor > minor) {
108188447a05SGarrett D'Amore break;
108288447a05SGarrett D'Amore }
108388447a05SGarrett D'Amore minor++;
108488447a05SGarrett D'Amore }
108588447a05SGarrett D'Amore if (minor >= MAXMIN32) {
108688447a05SGarrett D'Amore rw_exit(&auimpl_client_lock);
108788447a05SGarrett D'Amore goto failed;
108888447a05SGarrett D'Amore }
108988447a05SGarrett D'Amore c->c_minor = minor;
109088447a05SGarrett D'Amore list_insert_before(list, next, c);
109188447a05SGarrett D'Amore
109288447a05SGarrett D'Amore rw_exit(&auimpl_client_lock);
109388447a05SGarrett D'Amore
109488447a05SGarrett D'Amore
109588447a05SGarrett D'Amore return (c);
109688447a05SGarrett D'Amore
109788447a05SGarrett D'Amore failed:
109888447a05SGarrett D'Amore auimpl_dev_release(d);
109988447a05SGarrett D'Amore audio_stream_fini(&c->c_ostream);
110088447a05SGarrett D'Amore audio_stream_fini(&c->c_istream);
110188447a05SGarrett D'Amore mutex_destroy(&c->c_lock);
110288447a05SGarrett D'Amore cv_destroy(&c->c_cv);
110388447a05SGarrett D'Amore kmem_free(c, sizeof (*c));
110488447a05SGarrett D'Amore return (NULL);
110588447a05SGarrett D'Amore }
110688447a05SGarrett D'Amore
110788447a05SGarrett D'Amore void
auimpl_client_destroy(audio_client_t * c)110888447a05SGarrett D'Amore auimpl_client_destroy(audio_client_t *c)
110988447a05SGarrett D'Amore {
111088447a05SGarrett D'Amore /* remove us from the global list */
111188447a05SGarrett D'Amore rw_enter(&auimpl_client_lock, RW_WRITER);
111288447a05SGarrett D'Amore list_remove(&auimpl_clients, c);
111388447a05SGarrett D'Amore rw_exit(&auimpl_client_lock);
111488447a05SGarrett D'Amore
111588447a05SGarrett D'Amore ASSERT(!c->c_istream.s_running);
1116*4a2cf368SZhao Edgar Liu - Sun Microsystems ASSERT(!c->c_ostream.s_running);
111788447a05SGarrett D'Amore
111888447a05SGarrett D'Amore /* release the device reference count */
111988447a05SGarrett D'Amore auimpl_dev_release(c->c_dev);
112088447a05SGarrett D'Amore c->c_dev = NULL;
112188447a05SGarrett D'Amore
112288447a05SGarrett D'Amore mutex_destroy(&c->c_lock);
112388447a05SGarrett D'Amore cv_destroy(&c->c_cv);
112488447a05SGarrett D'Amore
112588447a05SGarrett D'Amore audio_stream_fini(&c->c_istream);
112688447a05SGarrett D'Amore audio_stream_fini(&c->c_ostream);
112788447a05SGarrett D'Amore kmem_free(c, sizeof (*c));
112888447a05SGarrett D'Amore }
112988447a05SGarrett D'Amore
113053a539a7SGarrett D'Amore void
auimpl_client_activate(audio_client_t * c)113153a539a7SGarrett D'Amore auimpl_client_activate(audio_client_t *c)
113253a539a7SGarrett D'Amore {
113353a539a7SGarrett D'Amore rw_enter(&auimpl_client_lock, RW_WRITER);
113453a539a7SGarrett D'Amore c->c_is_active = B_TRUE;
113553a539a7SGarrett D'Amore rw_exit(&auimpl_client_lock);
113653a539a7SGarrett D'Amore }
113753a539a7SGarrett D'Amore
113853a539a7SGarrett D'Amore void
auimpl_client_deactivate(audio_client_t * c)113953a539a7SGarrett D'Amore auimpl_client_deactivate(audio_client_t *c)
114053a539a7SGarrett D'Amore {
114153a539a7SGarrett D'Amore rw_enter(&auimpl_client_lock, RW_WRITER);
114253a539a7SGarrett D'Amore c->c_is_active = B_FALSE;
114353a539a7SGarrett D'Amore rw_exit(&auimpl_client_lock);
114453a539a7SGarrett D'Amore }
114553a539a7SGarrett D'Amore
114688447a05SGarrett D'Amore void
auclnt_close(audio_client_t * c)114788447a05SGarrett D'Amore auclnt_close(audio_client_t *c)
114888447a05SGarrett D'Amore {
114988447a05SGarrett D'Amore audio_dev_t *d = c->c_dev;
115088447a05SGarrett D'Amore
115188447a05SGarrett D'Amore /* stop the engines if they are running */
115288447a05SGarrett D'Amore auclnt_stop(&c->c_istream);
115388447a05SGarrett D'Amore auclnt_stop(&c->c_ostream);
115488447a05SGarrett D'Amore
115553a539a7SGarrett D'Amore rw_enter(&auimpl_client_lock, RW_WRITER);
115688447a05SGarrett D'Amore list_remove(&d->d_clients, c);
115753a539a7SGarrett D'Amore rw_exit(&auimpl_client_lock);
115888447a05SGarrett D'Amore
115988447a05SGarrett D'Amore mutex_enter(&c->c_lock);
116088447a05SGarrett D'Amore /* if in transition need to wait for other thread to release */
116188447a05SGarrett D'Amore while (c->c_refcnt) {
116288447a05SGarrett D'Amore cv_wait(&c->c_cv, &c->c_lock);
116388447a05SGarrett D'Amore }
116488447a05SGarrett D'Amore mutex_exit(&c->c_lock);
116588447a05SGarrett D'Amore
116688447a05SGarrett D'Amore /* release any engines that we were holding */
116788447a05SGarrett D'Amore auimpl_engine_close(&c->c_ostream);
116888447a05SGarrett D'Amore auimpl_engine_close(&c->c_istream);
116988447a05SGarrett D'Amore }
117088447a05SGarrett D'Amore
117188447a05SGarrett D'Amore audio_dev_t *
auclnt_hold_dev_by_index(int index)117288447a05SGarrett D'Amore auclnt_hold_dev_by_index(int index)
117388447a05SGarrett D'Amore {
117488447a05SGarrett D'Amore return (auimpl_dev_hold_by_index(index));
117588447a05SGarrett D'Amore }
117688447a05SGarrett D'Amore
117788447a05SGarrett D'Amore void
auclnt_release_dev(audio_dev_t * dev)117888447a05SGarrett D'Amore auclnt_release_dev(audio_dev_t *dev)
117988447a05SGarrett D'Amore {
118088447a05SGarrett D'Amore auimpl_dev_release(dev);
118188447a05SGarrett D'Amore }
118288447a05SGarrett D'Amore
118388447a05SGarrett D'Amore audio_client_t *
auclnt_hold_by_devt(dev_t dev)118488447a05SGarrett D'Amore auclnt_hold_by_devt(dev_t dev)
118588447a05SGarrett D'Amore {
118688447a05SGarrett D'Amore minor_t mn = getminor(dev);
118788447a05SGarrett D'Amore major_t mj = getmajor(dev);
118888447a05SGarrett D'Amore list_t *list;
118988447a05SGarrett D'Amore audio_client_t *c;
119088447a05SGarrett D'Amore
119188447a05SGarrett D'Amore list = &auimpl_clients;
119288447a05SGarrett D'Amore /* linked list search is kind of inefficient, but it works */
119388447a05SGarrett D'Amore rw_enter(&auimpl_client_lock, RW_READER);
119488447a05SGarrett D'Amore for (c = list_head(list); c != NULL; c = list_next(list, c)) {
119588447a05SGarrett D'Amore if ((c->c_major == mj) && (c->c_minor == mn)) {
119688447a05SGarrett D'Amore mutex_enter(&c->c_lock);
119753a539a7SGarrett D'Amore if (c->c_is_active) {
119888447a05SGarrett D'Amore c->c_refcnt++;
119988447a05SGarrett D'Amore mutex_exit(&c->c_lock);
120088447a05SGarrett D'Amore } else {
120188447a05SGarrett D'Amore mutex_exit(&c->c_lock);
120288447a05SGarrett D'Amore c = NULL;
120388447a05SGarrett D'Amore }
120488447a05SGarrett D'Amore break;
120588447a05SGarrett D'Amore }
120688447a05SGarrett D'Amore }
120788447a05SGarrett D'Amore rw_exit(&auimpl_client_lock);
120888447a05SGarrett D'Amore return (c);
120988447a05SGarrett D'Amore }
121088447a05SGarrett D'Amore
121168c47f65SGarrett D'Amore int
auclnt_serialize(audio_client_t * c)121268c47f65SGarrett D'Amore auclnt_serialize(audio_client_t *c)
121368c47f65SGarrett D'Amore {
121468c47f65SGarrett D'Amore mutex_enter(&c->c_lock);
121568c47f65SGarrett D'Amore while (c->c_serialize) {
121668c47f65SGarrett D'Amore if (cv_wait_sig(&c->c_cv, &c->c_lock) == 0) {
121768c47f65SGarrett D'Amore mutex_exit(&c->c_lock);
121868c47f65SGarrett D'Amore return (EINTR);
121968c47f65SGarrett D'Amore }
122068c47f65SGarrett D'Amore }
122168c47f65SGarrett D'Amore c->c_serialize = B_TRUE;
122268c47f65SGarrett D'Amore mutex_exit(&c->c_lock);
122368c47f65SGarrett D'Amore return (0);
122468c47f65SGarrett D'Amore }
122568c47f65SGarrett D'Amore
122668c47f65SGarrett D'Amore void
auclnt_unserialize(audio_client_t * c)122768c47f65SGarrett D'Amore auclnt_unserialize(audio_client_t *c)
122868c47f65SGarrett D'Amore {
122968c47f65SGarrett D'Amore mutex_enter(&c->c_lock);
123068c47f65SGarrett D'Amore ASSERT(c->c_serialize);
123168c47f65SGarrett D'Amore c->c_serialize = B_FALSE;
123268c47f65SGarrett D'Amore cv_broadcast(&c->c_cv);
123368c47f65SGarrett D'Amore mutex_exit(&c->c_lock);
123468c47f65SGarrett D'Amore }
123568c47f65SGarrett D'Amore
123668c47f65SGarrett D'Amore void
auclnt_hold(audio_client_t * c)123768c47f65SGarrett D'Amore auclnt_hold(audio_client_t *c)
123868c47f65SGarrett D'Amore {
123968c47f65SGarrett D'Amore mutex_enter(&c->c_lock);
124068c47f65SGarrett D'Amore c->c_refcnt++;
124168c47f65SGarrett D'Amore mutex_exit(&c->c_lock);
124268c47f65SGarrett D'Amore }
124368c47f65SGarrett D'Amore
124488447a05SGarrett D'Amore void
auclnt_release(audio_client_t * c)124588447a05SGarrett D'Amore auclnt_release(audio_client_t *c)
124688447a05SGarrett D'Amore {
124788447a05SGarrett D'Amore mutex_enter(&c->c_lock);
1248a19bb1faSGarrett D'Amore ASSERT(c->c_refcnt > 0);
124988447a05SGarrett D'Amore c->c_refcnt--;
125088447a05SGarrett D'Amore if (c->c_refcnt == 0)
125188447a05SGarrett D'Amore cv_broadcast(&c->c_cv);
125288447a05SGarrett D'Amore mutex_exit(&c->c_lock);
125388447a05SGarrett D'Amore }
125488447a05SGarrett D'Amore
125568c47f65SGarrett D'Amore uint_t
auclnt_dev_get_serial(audio_dev_t * d)1256682cb104SGarrett D'Amore auclnt_dev_get_serial(audio_dev_t *d)
1257682cb104SGarrett D'Amore {
1258682cb104SGarrett D'Amore return (d->d_serial);
1259682cb104SGarrett D'Amore }
1260682cb104SGarrett D'Amore
126188447a05SGarrett D'Amore void
auclnt_dev_walk_clients(audio_dev_t * d,int (* walker)(audio_client_t *,void *),void * arg)126288447a05SGarrett D'Amore auclnt_dev_walk_clients(audio_dev_t *d,
126388447a05SGarrett D'Amore int (*walker)(audio_client_t *, void *),
126488447a05SGarrett D'Amore void *arg)
126588447a05SGarrett D'Amore {
126688447a05SGarrett D'Amore list_t *l = &d->d_clients;
126788447a05SGarrett D'Amore audio_client_t *c;
126888447a05SGarrett D'Amore int rv;
126988447a05SGarrett D'Amore
127053a539a7SGarrett D'Amore rw_enter(&auimpl_client_lock, RW_READER);
127188447a05SGarrett D'Amore restart:
127288447a05SGarrett D'Amore for (c = list_head(l); c != NULL; c = list_next(l, c)) {
127353a539a7SGarrett D'Amore if (!c->c_is_active)
127453a539a7SGarrett D'Amore continue;
127588447a05SGarrett D'Amore rv = (walker(c, arg));
127688447a05SGarrett D'Amore if (rv == AUDIO_WALK_STOP) {
127788447a05SGarrett D'Amore break;
127888447a05SGarrett D'Amore } else if (rv == AUDIO_WALK_RESTART) {
127988447a05SGarrett D'Amore goto restart;
128088447a05SGarrett D'Amore }
128188447a05SGarrett D'Amore }
128253a539a7SGarrett D'Amore rw_exit(&auimpl_client_lock);
128388447a05SGarrett D'Amore }
128488447a05SGarrett D'Amore
128588447a05SGarrett D'Amore
128688447a05SGarrett D'Amore int
auclnt_open(audio_client_t * c,int oflag)12872c30fa45SGarrett D'Amore auclnt_open(audio_client_t *c, int oflag)
128888447a05SGarrett D'Amore {
128988447a05SGarrett D'Amore audio_stream_t *sp;
129088447a05SGarrett D'Amore audio_dev_t *d = c->c_dev;
129188447a05SGarrett D'Amore int rv = 0;
129288447a05SGarrett D'Amore int flags;
129388447a05SGarrett D'Amore
129488447a05SGarrett D'Amore flags = 0;
129588447a05SGarrett D'Amore if (oflag & FNDELAY)
129688447a05SGarrett D'Amore flags |= ENGINE_NDELAY;
129788447a05SGarrett D'Amore
129888447a05SGarrett D'Amore if (oflag & FWRITE) {
129988447a05SGarrett D'Amore sp = &c->c_ostream;
13002c30fa45SGarrett D'Amore if ((rv = auimpl_engine_open(sp, flags | ENGINE_OUTPUT)) != 0)
130188447a05SGarrett D'Amore goto done;
130288447a05SGarrett D'Amore }
130388447a05SGarrett D'Amore
130488447a05SGarrett D'Amore if (oflag & FREAD) {
130588447a05SGarrett D'Amore sp = &c->c_istream;
13062c30fa45SGarrett D'Amore if ((rv = auimpl_engine_open(sp, flags | ENGINE_INPUT)) != 0)
130788447a05SGarrett D'Amore goto done;
130888447a05SGarrett D'Amore }
130988447a05SGarrett D'Amore
131088447a05SGarrett D'Amore done:
131188447a05SGarrett D'Amore if (rv != 0) {
131288447a05SGarrett D'Amore /* close any engines that we opened */
131388447a05SGarrett D'Amore auimpl_engine_close(&c->c_ostream);
131488447a05SGarrett D'Amore auimpl_engine_close(&c->c_istream);
131588447a05SGarrett D'Amore } else {
131653a539a7SGarrett D'Amore rw_enter(&auimpl_client_lock, RW_WRITER);
131788447a05SGarrett D'Amore list_insert_tail(&d->d_clients, c);
131888447a05SGarrett D'Amore c->c_ostream.s_gain_master = d->d_pcmvol;
131988447a05SGarrett D'Amore c->c_istream.s_gain_master = 100;
132053a539a7SGarrett D'Amore rw_exit(&auimpl_client_lock);
132188447a05SGarrett D'Amore auclnt_set_gain(&c->c_ostream, 100);
132288447a05SGarrett D'Amore auclnt_set_gain(&c->c_istream, 100);
132388447a05SGarrett D'Amore }
132488447a05SGarrett D'Amore
132588447a05SGarrett D'Amore return (rv);
132688447a05SGarrett D'Amore }
132788447a05SGarrett D'Amore
132888447a05SGarrett D'Amore minor_t
auclnt_get_minor(audio_client_t * c)132988447a05SGarrett D'Amore auclnt_get_minor(audio_client_t *c)
133088447a05SGarrett D'Amore {
133188447a05SGarrett D'Amore return (c->c_minor);
133288447a05SGarrett D'Amore }
133388447a05SGarrett D'Amore
133488447a05SGarrett D'Amore minor_t
auclnt_get_original_minor(audio_client_t * c)133588447a05SGarrett D'Amore auclnt_get_original_minor(audio_client_t *c)
133688447a05SGarrett D'Amore {
133788447a05SGarrett D'Amore return (c->c_origminor);
133888447a05SGarrett D'Amore }
133988447a05SGarrett D'Amore
134088447a05SGarrett D'Amore minor_t
auclnt_get_minor_type(audio_client_t * c)134188447a05SGarrett D'Amore auclnt_get_minor_type(audio_client_t *c)
134288447a05SGarrett D'Amore {
134388447a05SGarrett D'Amore return (c->c_origminor & AUDIO_MN_TYPE_MASK);
134488447a05SGarrett D'Amore }
134588447a05SGarrett D'Amore
1346a19bb1faSGarrett D'Amore queue_t *
auclnt_get_rq(audio_client_t * c)1347a19bb1faSGarrett D'Amore auclnt_get_rq(audio_client_t *c)
1348a19bb1faSGarrett D'Amore {
1349a19bb1faSGarrett D'Amore return (c->c_rq);
1350a19bb1faSGarrett D'Amore }
1351a19bb1faSGarrett D'Amore
1352a19bb1faSGarrett D'Amore queue_t *
auclnt_get_wq(audio_client_t * c)1353a19bb1faSGarrett D'Amore auclnt_get_wq(audio_client_t *c)
1354a19bb1faSGarrett D'Amore {
1355a19bb1faSGarrett D'Amore return (c->c_wq);
1356a19bb1faSGarrett D'Amore }
1357a19bb1faSGarrett D'Amore
135888447a05SGarrett D'Amore pid_t
auclnt_get_pid(audio_client_t * c)135988447a05SGarrett D'Amore auclnt_get_pid(audio_client_t *c)
136088447a05SGarrett D'Amore {
136188447a05SGarrett D'Amore return (c->c_pid);
136288447a05SGarrett D'Amore }
136388447a05SGarrett D'Amore
136488447a05SGarrett D'Amore cred_t *
auclnt_get_cred(audio_client_t * c)136588447a05SGarrett D'Amore auclnt_get_cred(audio_client_t *c)
136688447a05SGarrett D'Amore {
136788447a05SGarrett D'Amore return (c->c_cred);
136888447a05SGarrett D'Amore }
136988447a05SGarrett D'Amore
137088447a05SGarrett D'Amore audio_dev_t *
auclnt_get_dev(audio_client_t * c)137188447a05SGarrett D'Amore auclnt_get_dev(audio_client_t *c)
137288447a05SGarrett D'Amore {
137388447a05SGarrett D'Amore return (c->c_dev);
137488447a05SGarrett D'Amore }
137588447a05SGarrett D'Amore
137688447a05SGarrett D'Amore int
auclnt_get_dev_number(audio_dev_t * dev)137788447a05SGarrett D'Amore auclnt_get_dev_number(audio_dev_t *dev)
137888447a05SGarrett D'Amore {
137988447a05SGarrett D'Amore return (dev->d_number);
138088447a05SGarrett D'Amore }
138188447a05SGarrett D'Amore
138288447a05SGarrett D'Amore int
auclnt_get_dev_index(audio_dev_t * dev)138388447a05SGarrett D'Amore auclnt_get_dev_index(audio_dev_t *dev)
138488447a05SGarrett D'Amore {
138588447a05SGarrett D'Amore return (dev->d_index);
138688447a05SGarrett D'Amore }
138788447a05SGarrett D'Amore
138888447a05SGarrett D'Amore const char *
auclnt_get_dev_name(audio_dev_t * dev)138988447a05SGarrett D'Amore auclnt_get_dev_name(audio_dev_t *dev)
139088447a05SGarrett D'Amore {
139188447a05SGarrett D'Amore return (dev->d_name);
139288447a05SGarrett D'Amore }
139388447a05SGarrett D'Amore
139488447a05SGarrett D'Amore const char *
auclnt_get_dev_driver(audio_dev_t * dev)139588447a05SGarrett D'Amore auclnt_get_dev_driver(audio_dev_t *dev)
139688447a05SGarrett D'Amore {
139788447a05SGarrett D'Amore return (ddi_driver_name(dev->d_dip));
139888447a05SGarrett D'Amore }
139988447a05SGarrett D'Amore
140088447a05SGarrett D'Amore dev_info_t *
auclnt_get_dev_devinfo(audio_dev_t * dev)140188447a05SGarrett D'Amore auclnt_get_dev_devinfo(audio_dev_t *dev)
140288447a05SGarrett D'Amore {
140388447a05SGarrett D'Amore return (dev->d_dip);
140488447a05SGarrett D'Amore }
140588447a05SGarrett D'Amore
140688447a05SGarrett D'Amore const char *
auclnt_get_dev_hw_info(audio_dev_t * dev,void ** iter)140788447a05SGarrett D'Amore auclnt_get_dev_hw_info(audio_dev_t *dev, void **iter)
140888447a05SGarrett D'Amore {
140988447a05SGarrett D'Amore struct audio_infostr *isp = *iter;
141088447a05SGarrett D'Amore if (isp == NULL) {
141188447a05SGarrett D'Amore isp = list_head(&dev->d_hwinfo);
141288447a05SGarrett D'Amore } else {
141388447a05SGarrett D'Amore isp = list_next(&dev->d_hwinfo, isp);
141488447a05SGarrett D'Amore }
141588447a05SGarrett D'Amore
141688447a05SGarrett D'Amore *iter = isp;
141788447a05SGarrett D'Amore return (isp ? isp->i_line : NULL);
141888447a05SGarrett D'Amore }
141988447a05SGarrett D'Amore
142088447a05SGarrett D'Amore int
auclnt_get_dev_instance(audio_dev_t * dev)142188447a05SGarrett D'Amore auclnt_get_dev_instance(audio_dev_t *dev)
142288447a05SGarrett D'Amore {
142388447a05SGarrett D'Amore return (dev->d_instance);
142488447a05SGarrett D'Amore }
142588447a05SGarrett D'Amore
142688447a05SGarrett D'Amore const char *
auclnt_get_dev_description(audio_dev_t * dev)142788447a05SGarrett D'Amore auclnt_get_dev_description(audio_dev_t *dev)
142888447a05SGarrett D'Amore {
142988447a05SGarrett D'Amore return (dev->d_desc);
143088447a05SGarrett D'Amore }
143188447a05SGarrett D'Amore
143288447a05SGarrett D'Amore const char *
auclnt_get_dev_version(audio_dev_t * dev)143388447a05SGarrett D'Amore auclnt_get_dev_version(audio_dev_t *dev)
143488447a05SGarrett D'Amore {
143588447a05SGarrett D'Amore return (dev->d_vers);
143688447a05SGarrett D'Amore }
143788447a05SGarrett D'Amore
143868c47f65SGarrett D'Amore uint_t
auclnt_get_dev_capab(audio_dev_t * dev)143988447a05SGarrett D'Amore auclnt_get_dev_capab(audio_dev_t *dev)
144088447a05SGarrett D'Amore {
144188447a05SGarrett D'Amore uint32_t flags;
144268c47f65SGarrett D'Amore uint_t caps = 0;
144388447a05SGarrett D'Amore
144488447a05SGarrett D'Amore flags = dev->d_flags;
144588447a05SGarrett D'Amore
144688447a05SGarrett D'Amore if (flags & DEV_OUTPUT_CAP)
144788447a05SGarrett D'Amore caps |= AUDIO_CLIENT_CAP_PLAY;
144888447a05SGarrett D'Amore if (flags & DEV_INPUT_CAP)
144988447a05SGarrett D'Amore caps |= AUDIO_CLIENT_CAP_RECORD;
145088447a05SGarrett D'Amore if (flags & DEV_DUPLEX_CAP)
145188447a05SGarrett D'Amore caps |= AUDIO_CLIENT_CAP_DUPLEX;
145288447a05SGarrett D'Amore
145388447a05SGarrett D'Amore /* AC3: deal with formats that don't support mixing */
145488447a05SGarrett D'Amore
145588447a05SGarrett D'Amore return (caps);
145688447a05SGarrett D'Amore }
145788447a05SGarrett D'Amore
145888447a05SGarrett D'Amore uint64_t
auclnt_get_samples(audio_stream_t * sp)145988447a05SGarrett D'Amore auclnt_get_samples(audio_stream_t *sp)
146088447a05SGarrett D'Amore {
146188447a05SGarrett D'Amore uint64_t n;
146288447a05SGarrett D'Amore
146388447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
146488447a05SGarrett D'Amore n = sp->s_samples;
146588447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
146688447a05SGarrett D'Amore return (n);
146788447a05SGarrett D'Amore }
146888447a05SGarrett D'Amore
146988447a05SGarrett D'Amore void
auclnt_set_samples(audio_stream_t * sp,uint64_t n)147088447a05SGarrett D'Amore auclnt_set_samples(audio_stream_t *sp, uint64_t n)
147188447a05SGarrett D'Amore {
147288447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
147388447a05SGarrett D'Amore sp->s_samples = n;
147488447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
147588447a05SGarrett D'Amore }
147688447a05SGarrett D'Amore
147788447a05SGarrett D'Amore uint64_t
auclnt_get_errors(audio_stream_t * sp)147888447a05SGarrett D'Amore auclnt_get_errors(audio_stream_t *sp)
147988447a05SGarrett D'Amore {
148088447a05SGarrett D'Amore uint64_t n;
148188447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
148288447a05SGarrett D'Amore n = sp->s_errors;
148388447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
148488447a05SGarrett D'Amore return (n);
148588447a05SGarrett D'Amore }
148688447a05SGarrett D'Amore
148788447a05SGarrett D'Amore void
auclnt_set_errors(audio_stream_t * sp,uint64_t n)148888447a05SGarrett D'Amore auclnt_set_errors(audio_stream_t *sp, uint64_t n)
148988447a05SGarrett D'Amore {
149088447a05SGarrett D'Amore mutex_enter(&sp->s_lock);
149188447a05SGarrett D'Amore sp->s_errors = n;
149288447a05SGarrett D'Amore mutex_exit(&sp->s_lock);
149388447a05SGarrett D'Amore }
149488447a05SGarrett D'Amore
149588447a05SGarrett D'Amore void
auclnt_register_ops(minor_t minor,audio_client_ops_t * ops)149688447a05SGarrett D'Amore auclnt_register_ops(minor_t minor, audio_client_ops_t *ops)
149788447a05SGarrett D'Amore {
149888447a05SGarrett D'Amore /* we control minor number allocations, no need for runtime checks */
149988447a05SGarrett D'Amore ASSERT(minor <= AUDIO_MN_TYPE_MASK);
150088447a05SGarrett D'Amore
150188447a05SGarrett D'Amore audio_client_ops[minor] = ops;
150288447a05SGarrett D'Amore }
150388447a05SGarrett D'Amore
150488447a05SGarrett D'Amore int
auimpl_create_minors(audio_dev_t * d)150588447a05SGarrett D'Amore auimpl_create_minors(audio_dev_t *d)
150688447a05SGarrett D'Amore {
150788447a05SGarrett D'Amore char path[MAXPATHLEN];
150888447a05SGarrett D'Amore int rv = 0;
150988447a05SGarrett D'Amore minor_t minor;
151088447a05SGarrett D'Amore audio_client_ops_t *ops;
151188447a05SGarrett D'Amore char *nt;
151288447a05SGarrett D'Amore
151388447a05SGarrett D'Amore for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) {
151488447a05SGarrett D'Amore
151588447a05SGarrett D'Amore if ((ops = audio_client_ops[i]) == NULL)
151688447a05SGarrett D'Amore continue;
151788447a05SGarrett D'Amore
151888447a05SGarrett D'Amore if (ops->aco_dev_init != NULL)
151988447a05SGarrett D'Amore d->d_minor_data[i] = ops->aco_dev_init(d);
152088447a05SGarrett D'Amore
152188447a05SGarrett D'Amore switch (i) {
152288447a05SGarrett D'Amore case AUDIO_MINOR_SNDSTAT:
152388447a05SGarrett D'Amore if (!(d->d_flags & DEV_SNDSTAT_CAP)) {
152488447a05SGarrett D'Amore continue;
152588447a05SGarrett D'Amore }
152688447a05SGarrett D'Amore nt = DDI_PSEUDO;
152788447a05SGarrett D'Amore break;
152888447a05SGarrett D'Amore
152988447a05SGarrett D'Amore default:
153088447a05SGarrett D'Amore if (!(d->d_flags & (DEV_INPUT_CAP| DEV_OUTPUT_CAP))) {
153188447a05SGarrett D'Amore continue;
153288447a05SGarrett D'Amore }
153388447a05SGarrett D'Amore nt = DDI_NT_AUDIO;
153488447a05SGarrett D'Amore break;
153588447a05SGarrett D'Amore }
153688447a05SGarrett D'Amore
153788447a05SGarrett D'Amore if (ops->aco_minor_prefix != NULL) {
153888447a05SGarrett D'Amore
153988447a05SGarrett D'Amore minor = AUDIO_MKMN(d->d_instance, i);
154088447a05SGarrett D'Amore (void) snprintf(path, sizeof (path),
154188447a05SGarrett D'Amore "%s%d", ops->aco_minor_prefix, d->d_instance);
154288447a05SGarrett D'Amore
154388447a05SGarrett D'Amore rv = ddi_create_minor_node(d->d_dip, path, S_IFCHR,
154488447a05SGarrett D'Amore minor, nt, 0);
154588447a05SGarrett D'Amore
154688447a05SGarrett D'Amore if (rv != 0)
154788447a05SGarrett D'Amore break;
154888447a05SGarrett D'Amore }
154988447a05SGarrett D'Amore }
155088447a05SGarrett D'Amore return (rv);
155188447a05SGarrett D'Amore }
155288447a05SGarrett D'Amore
155388447a05SGarrett D'Amore void
auimpl_remove_minors(audio_dev_t * d)155488447a05SGarrett D'Amore auimpl_remove_minors(audio_dev_t *d)
155588447a05SGarrett D'Amore {
155688447a05SGarrett D'Amore char path[MAXPATHLEN];
155788447a05SGarrett D'Amore audio_client_ops_t *ops;
155888447a05SGarrett D'Amore
155988447a05SGarrett D'Amore for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) {
156088447a05SGarrett D'Amore if ((ops = audio_client_ops[i]) == NULL)
156188447a05SGarrett D'Amore continue;
156288447a05SGarrett D'Amore if (ops->aco_minor_prefix != NULL) {
156388447a05SGarrett D'Amore (void) snprintf(path, sizeof (path), "%s%d",
156488447a05SGarrett D'Amore ops->aco_minor_prefix, d->d_instance);
156588447a05SGarrett D'Amore (void) ddi_remove_minor_node(d->d_dip, path);
156688447a05SGarrett D'Amore }
156788447a05SGarrett D'Amore
156888447a05SGarrett D'Amore if (ops->aco_dev_fini != NULL)
156988447a05SGarrett D'Amore ops->aco_dev_fini(d->d_minor_data[i]);
157088447a05SGarrett D'Amore }
157188447a05SGarrett D'Amore }
157288447a05SGarrett D'Amore
157388447a05SGarrett D'Amore void *
auclnt_get_dev_minor_data(audio_dev_t * d,minor_t mn)157488447a05SGarrett D'Amore auclnt_get_dev_minor_data(audio_dev_t *d, minor_t mn)
157588447a05SGarrett D'Amore {
157688447a05SGarrett D'Amore ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS));
157788447a05SGarrett D'Amore return (d->d_minor_data[mn]);
157888447a05SGarrett D'Amore }
157988447a05SGarrett D'Amore
158088447a05SGarrett D'Amore void *
auclnt_get_minor_data(audio_client_t * c,minor_t mn)158188447a05SGarrett D'Amore auclnt_get_minor_data(audio_client_t *c, minor_t mn)
158288447a05SGarrett D'Amore {
158388447a05SGarrett D'Amore ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS));
158488447a05SGarrett D'Amore return (c->c_dev->d_minor_data[mn]);
158588447a05SGarrett D'Amore }
158688447a05SGarrett D'Amore
158788447a05SGarrett D'Amore /*
158888447a05SGarrett D'Amore * This will walk all controls registered to a clients device and callback
158988447a05SGarrett D'Amore * to walker for each one with its audio_ctrl. Note this data
159088447a05SGarrett D'Amore * must be considered read only by walker.
159188447a05SGarrett D'Amore *
159288447a05SGarrett D'Amore * Note that walk_func may return values to continue (AUDIO_WALK_CONTINUE)
159388447a05SGarrett D'Amore * or stop walk (AUDIO_WALK_STOP).
159488447a05SGarrett D'Amore *
159588447a05SGarrett D'Amore */
159688447a05SGarrett D'Amore void
auclnt_walk_controls(audio_dev_t * d,int (* walker)(audio_ctrl_t *,void *),void * arg)159788447a05SGarrett D'Amore auclnt_walk_controls(audio_dev_t *d,
159888447a05SGarrett D'Amore int (*walker)(audio_ctrl_t *, void *),
159988447a05SGarrett D'Amore void *arg)
160088447a05SGarrett D'Amore {
160188447a05SGarrett D'Amore audio_ctrl_t *ctrl;
160288447a05SGarrett D'Amore
160368c47f65SGarrett D'Amore mutex_enter(&d->d_ctrl_lock);
160488447a05SGarrett D'Amore for (ctrl = list_head(&d->d_controls); ctrl;
160588447a05SGarrett D'Amore ctrl = list_next(&d->d_controls, ctrl)) {
160688447a05SGarrett D'Amore if (walker(ctrl, arg) == AUDIO_WALK_STOP)
160788447a05SGarrett D'Amore break;
160888447a05SGarrett D'Amore }
160968c47f65SGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
161088447a05SGarrett D'Amore }
161188447a05SGarrett D'Amore
161288447a05SGarrett D'Amore /*
161388447a05SGarrett D'Amore * This will search all controls attached to an
161488447a05SGarrett D'Amore * audio device for a control with the desired name.
161588447a05SGarrett D'Amore *
161688447a05SGarrett D'Amore * d - the audio device to look on
161788447a05SGarrett D'Amore * name - name of the control being looked for.
161888447a05SGarrett D'Amore *
161988447a05SGarrett D'Amore * On successful return a ctrl handle will be returned. On
162088447a05SGarrett D'Amore * failure NULL is returned.
162188447a05SGarrett D'Amore */
162288447a05SGarrett D'Amore audio_ctrl_t *
auclnt_find_control(audio_dev_t * d,const char * name)162388447a05SGarrett D'Amore auclnt_find_control(audio_dev_t *d, const char *name)
162488447a05SGarrett D'Amore {
162588447a05SGarrett D'Amore audio_ctrl_t *ctrl;
162688447a05SGarrett D'Amore
162788447a05SGarrett D'Amore /* Verify argument */
162888447a05SGarrett D'Amore ASSERT(d);
162988447a05SGarrett D'Amore
163068c47f65SGarrett D'Amore mutex_enter(&d->d_ctrl_lock);
163188447a05SGarrett D'Amore for (ctrl = list_head(&d->d_controls); ctrl;
163288447a05SGarrett D'Amore ctrl = list_next(&d->d_controls, ctrl)) {
163388447a05SGarrett D'Amore if (strcmp(ctrl->ctrl_name, name) == 0) {
163468c47f65SGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
163588447a05SGarrett D'Amore return (ctrl);
163688447a05SGarrett D'Amore }
163788447a05SGarrett D'Amore }
163868c47f65SGarrett D'Amore mutex_exit(&d->d_ctrl_lock);
163988447a05SGarrett D'Amore return (NULL);
164088447a05SGarrett D'Amore }
164188447a05SGarrett D'Amore
164288447a05SGarrett D'Amore /*
164388447a05SGarrett D'Amore * Given a known control, get its attributes.
164488447a05SGarrett D'Amore *
164588447a05SGarrett D'Amore * The caller must supply a audio_ctrl_desc_t structure. Also the
164688447a05SGarrett D'Amore * values in the structure are ignored when making the call and filled
164788447a05SGarrett D'Amore * in by this function. All data pointed to by elements of desc should
164888447a05SGarrett D'Amore * be assumed read only.
164988447a05SGarrett D'Amore *
165088447a05SGarrett D'Amore * If an error occurs then a non-zero is returned.
165188447a05SGarrett D'Amore *
165288447a05SGarrett D'Amore */
165388447a05SGarrett D'Amore int
auclnt_control_describe(audio_ctrl_t * ctrl,audio_ctrl_desc_t * desc)165488447a05SGarrett D'Amore auclnt_control_describe(audio_ctrl_t *ctrl, audio_ctrl_desc_t *desc)
165588447a05SGarrett D'Amore {
165688447a05SGarrett D'Amore ASSERT(ctrl);
165788447a05SGarrett D'Amore ASSERT(desc);
165888447a05SGarrett D'Amore
165988447a05SGarrett D'Amore bcopy(&ctrl->ctrl_des, desc, sizeof (*desc));
166088447a05SGarrett D'Amore return (0);
166188447a05SGarrett D'Amore }
166288447a05SGarrett D'Amore
166388447a05SGarrett D'Amore int
auclnt_control_read(audio_ctrl_t * ctrl,uint64_t * value)166488447a05SGarrett D'Amore auclnt_control_read(audio_ctrl_t *ctrl, uint64_t *value)
166588447a05SGarrett D'Amore {
166688447a05SGarrett D'Amore return (audio_control_read(ctrl, value));
166788447a05SGarrett D'Amore }
166888447a05SGarrett D'Amore
166988447a05SGarrett D'Amore int
auclnt_control_write(audio_ctrl_t * ctrl,uint64_t value)167088447a05SGarrett D'Amore auclnt_control_write(audio_ctrl_t *ctrl, uint64_t value)
167188447a05SGarrett D'Amore {
167288447a05SGarrett D'Amore return (audio_control_write(ctrl, value));
167388447a05SGarrett D'Amore }
167488447a05SGarrett D'Amore
167588447a05SGarrett D'Amore void
auclnt_warn(audio_client_t * c,const char * fmt,...)167688447a05SGarrett D'Amore auclnt_warn(audio_client_t *c, const char *fmt, ...)
167788447a05SGarrett D'Amore {
167888447a05SGarrett D'Amore va_list va;
167988447a05SGarrett D'Amore
168088447a05SGarrett D'Amore va_start(va, fmt);
168188447a05SGarrett D'Amore auimpl_dev_vwarn(c ? c->c_dev : NULL, fmt, va);
168288447a05SGarrett D'Amore va_end(va);
168388447a05SGarrett D'Amore }
1684