Unleashed v1.4
[unleashed.git] / usr / src / uts / common / io / audio / impl / audio_client.c
blob75a4ffe6e4db6947971f51e8c717300b4f9e7498
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (C) 4Front Technologies 1996-2008.
24 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 #include <sys/types.h>
28 #include <sys/sysmacros.h>
29 #include <sys/list.h>
30 #include <sys/file.h>
31 #include <sys/open.h>
32 #include <sys/stat.h>
33 #include <sys/errno.h>
34 #include <sys/atomic.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
38 #include "audio_impl.h"
41 * Audio Client implementation.
45 * Attenuation table for dB->linear conversion. Indexed in steps of
46 * 0.5 dB. Table size is 25 dB (first entry is handled as mute).
48 * Notably, the last item in table is taken as 0 dB (i.e. maximum volume).
50 * Table contents can be calculated as follows (requires sunmath library):
52 * scale = AUDIO_VOL_SCALE;
53 * for (i = -50; i <= 0; i++) {
54 * x = exp10(0.05 * i);
55 * printf("%d: %f %.0f\n", i, x, trunc(x * scale));
56 * }
60 static const uint16_t auimpl_db_table[AUDIO_DB_SIZE + 1] = {
61 0, 0, 1, 1, 1, 1, 1, 1, 2, 2,
62 2, 2, 3, 3, 4, 4, 5, 5, 6, 7,
63 8, 9, 10, 11, 12, 14, 16, 18, 20, 22,
64 25, 28, 32, 36, 40, 45, 51, 57, 64, 72,
65 80, 90, 101, 114, 128, 143, 161, 181, 203, 228,
66 256
69 static list_t auimpl_clients;
70 static krwlock_t auimpl_client_lock;
71 static audio_client_ops_t *audio_client_ops[AUDIO_MN_TYPE_MASK + 1];
73 void *
74 auclnt_get_private(audio_client_t *c)
76 return (c->c_private);
79 void
80 auclnt_set_private(audio_client_t *c, void *private)
82 c->c_private = private;
85 int
86 auclnt_set_rate(audio_stream_t *sp, int rate)
88 audio_parms_t parms;
89 int rv = 0;
91 /* basic sanity checks! */
92 if ((rate < 5000) || (rate > 192000)) {
93 return (EINVAL);
95 if (rate != sp->s_user_parms->p_rate) {
96 parms.p_rate = rate;
97 rv = auimpl_engine_setup(sp, 0, &parms, FORMAT_MSK_RATE);
99 return (rv);
103 auclnt_get_rate(audio_stream_t *sp)
105 return (sp->s_user_parms->p_rate);
108 uint_t
109 auclnt_get_fragsz(audio_stream_t *sp)
111 return (sp->s_fragbytes);
114 uint_t
115 auclnt_get_framesz(audio_stream_t *sp)
117 return (sp->s_framesz);
120 uint_t
121 auclnt_get_nfrags(audio_stream_t *sp)
123 return (sp->s_nfrags);
126 uint_t
127 auclnt_get_nframes(audio_stream_t *sp)
129 return (sp->s_nframes);
132 void
133 auclnt_set_latency(audio_stream_t *sp, uint_t frags, uint_t bytes)
135 mutex_enter(&sp->s_lock);
136 sp->s_hintfrags = (uint16_t)frags;
137 sp->s_hintsz = bytes;
138 mutex_exit(&sp->s_lock);
141 uint64_t
142 auclnt_get_head(audio_stream_t *sp)
144 return (sp->s_head);
147 uint64_t
148 auclnt_get_tail(audio_stream_t *sp)
150 return (sp->s_tail);
153 uint_t
154 auclnt_get_hidx(audio_stream_t *sp)
156 return (sp->s_hidx);
159 uint_t
160 auclnt_get_tidx(audio_stream_t *sp)
162 return (sp->s_tidx);
165 audio_stream_t *
166 auclnt_input_stream(audio_client_t *c)
168 return (&c->c_istream);
171 audio_stream_t *
172 auclnt_output_stream(audio_client_t *c)
174 return (&c->c_ostream);
177 uint_t
178 auclnt_get_count(audio_stream_t *sp)
180 uint_t count;
182 mutex_enter(&sp->s_lock);
183 ASSERT((sp->s_head - sp->s_tail) <= sp->s_nframes);
184 count = (uint_t)(sp->s_head - sp->s_tail);
185 mutex_exit(&sp->s_lock);
187 return (count);
190 uint_t
191 auclnt_consume(audio_stream_t *sp, uint_t n)
193 mutex_enter(&sp->s_lock);
195 ASSERT(sp == &sp->s_client->c_istream);
196 n = max(n, sp->s_head - sp->s_tail);
197 sp->s_tail += n;
198 sp->s_tidx += n;
199 if (sp->s_tidx >= sp->s_nframes) {
200 sp->s_tidx -= sp->s_nframes;
203 ASSERT(sp->s_tail <= sp->s_head);
204 ASSERT(sp->s_hidx < sp->s_nframes);
206 mutex_exit(&sp->s_lock);
208 return (n);
211 uint_t
212 auclnt_consume_data(audio_stream_t *sp, caddr_t dst, uint_t n)
214 uint_t nframes;
215 uint_t framesz;
216 uint_t cnt;
217 caddr_t data;
219 mutex_enter(&sp->s_lock);
221 nframes = sp->s_nframes;
222 framesz = sp->s_framesz;
224 ASSERT(sp == &sp->s_client->c_istream);
225 ASSERT(sp->s_head >= sp->s_tail);
226 ASSERT(sp->s_tidx < nframes);
227 ASSERT(sp->s_hidx < nframes);
229 cnt = n = min(n, sp->s_head - sp->s_tail);
230 data = sp->s_data + (sp->s_tidx * framesz);
231 do {
232 uint_t nf, nb;
234 nf = min(nframes - sp->s_tidx, n);
235 nb = nf * framesz;
237 bcopy(data, dst, nb);
238 dst += nb;
239 data += nb;
241 n -= nf;
242 sp->s_tail += nf;
243 sp->s_tidx += nf;
244 if (sp->s_tidx == nframes) {
245 sp->s_tidx = 0;
246 data = sp->s_data;
248 } while (n);
250 ASSERT(sp->s_tail <= sp->s_head);
251 ASSERT(sp->s_tidx < nframes);
253 mutex_exit(&sp->s_lock);
255 return (cnt);
258 uint_t
259 auclnt_produce(audio_stream_t *sp, uint_t n)
261 mutex_enter(&sp->s_lock);
263 ASSERT(sp == &sp->s_client->c_ostream);
264 n = max(n, sp->s_nframes - (sp->s_head - sp->s_tail));
265 sp->s_head += n;
266 sp->s_hidx += n;
267 if (sp->s_hidx >= sp->s_nframes) {
268 sp->s_hidx -= sp->s_nframes;
271 ASSERT(sp->s_tail <= sp->s_head);
272 ASSERT(sp->s_hidx < sp->s_nframes);
274 mutex_exit(&sp->s_lock);
276 return (n);
279 uint_t
280 auclnt_produce_data(audio_stream_t *sp, caddr_t src, uint_t n)
282 uint_t nframes;
283 uint_t framesz;
284 uint_t cnt;
285 caddr_t data;
287 mutex_enter(&sp->s_lock);
289 nframes = sp->s_nframes;
290 framesz = sp->s_framesz;
292 ASSERT(sp == &sp->s_client->c_ostream);
293 ASSERT(sp->s_head >= sp->s_tail);
294 ASSERT(sp->s_tidx < nframes);
295 ASSERT(sp->s_hidx < nframes);
297 cnt = n = min(n, nframes - (sp->s_head - sp->s_tail));
298 data = sp->s_data + (sp->s_hidx * framesz);
299 do {
300 uint_t nf, nb;
302 nf = min(nframes - sp->s_hidx, n);
303 nb = nf * framesz;
305 bcopy(src, data, nb);
307 src += nb;
308 data += nb;
310 n -= nf;
311 sp->s_head += nf;
312 sp->s_hidx += nf;
313 if (sp->s_hidx == nframes) {
314 sp->s_hidx = 0;
315 data = sp->s_data;
317 } while (n);
319 ASSERT(sp->s_tail <= sp->s_head);
320 ASSERT(sp->s_hidx < nframes);
322 mutex_exit(&sp->s_lock);
324 return (cnt);
328 auclnt_read(audio_client_t *c, struct uio *uio)
330 audio_stream_t *sp = &c->c_istream;
331 uint_t cnt;
332 int rv = 0;
333 offset_t loff;
334 int eagain;
335 uint_t tidx;
336 uint_t framesz;
338 loff = uio->uio_loffset;
339 eagain = EAGAIN;
341 mutex_enter(&sp->s_lock);
343 if ((!sp->s_paused) && (!sp->s_running)) {
344 mutex_exit(&sp->s_lock);
345 auclnt_start(sp);
346 mutex_enter(&sp->s_lock);
350 framesz = sp->s_framesz;
352 ASSERT(sp->s_head >= sp->s_tail);
353 ASSERT(sp->s_tidx < sp->s_nframes);
355 while (uio->uio_resid >= framesz) {
357 while ((cnt = (sp->s_head - sp->s_tail)) == 0) {
358 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
359 mutex_exit(&sp->s_lock);
360 return (eagain);
362 if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
363 mutex_exit(&sp->s_lock);
364 return (EINTR);
368 tidx = sp->s_tidx;
369 cnt = min(cnt, sp->s_nframes - tidx);
370 cnt = min(cnt, (uio->uio_resid / framesz));
372 mutex_exit(&sp->s_lock);
373 rv = uiomove(sp->s_data + (tidx * framesz),
374 cnt * framesz, UIO_READ, uio);
376 uio->uio_loffset = loff;
377 eagain = 0;
379 if (rv != 0) {
380 return (rv);
383 mutex_enter(&sp->s_lock);
384 sp->s_tail += cnt;
385 sp->s_tidx += cnt;
386 if (sp->s_tidx == sp->s_nframes) {
387 sp->s_tidx = 0;
391 ASSERT(sp->s_tail <= sp->s_head);
392 ASSERT(sp->s_tidx < sp->s_nframes);
394 /* round off any remaining partial bits */
395 uio->uio_resid = 0;
397 mutex_exit(&sp->s_lock);
399 return (rv);
403 auclnt_write(audio_client_t *c, struct uio *uio)
405 audio_stream_t *sp = &c->c_ostream;
406 uint_t cnt;
407 int rv = 0;
408 offset_t loff;
409 int eagain;
410 uint_t framesz;
411 uint_t hidx;
413 loff = uio->uio_loffset;
414 eagain = EAGAIN;
416 mutex_enter(&sp->s_lock);
418 framesz = sp->s_framesz;
420 ASSERT(sp->s_head >= sp->s_tail);
421 ASSERT(sp->s_hidx < sp->s_nframes);
423 while (uio->uio_resid >= framesz) {
425 while ((cnt = sp->s_nframes - (sp->s_head - sp->s_tail)) == 0) {
426 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
427 mutex_exit(&sp->s_lock);
428 return (eagain);
430 if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
431 mutex_exit(&sp->s_lock);
432 return (EINTR);
436 hidx = sp->s_hidx;
437 cnt = min(cnt, sp->s_nframes - hidx);
438 cnt = min(cnt, (uio->uio_resid / framesz));
441 * We have to drop the stream lock, because the
442 * uiomove might require doing a page in, which could
443 * get blocked behind the PIL of the audio processing
444 * thread which also grabs the s_lock. (Hence, there
445 * is a risk of deadlock due to priority inversion.)
447 mutex_exit(&sp->s_lock);
449 rv = uiomove(sp->s_data + (hidx * framesz),
450 cnt * framesz, UIO_WRITE, uio);
452 uio->uio_loffset = loff;
453 eagain = 0;
455 if (rv != 0) {
456 return (rv);
459 mutex_enter(&sp->s_lock);
461 sp->s_head += cnt;
462 sp->s_hidx += cnt;
463 if (sp->s_hidx == sp->s_nframes) {
464 sp->s_hidx = 0;
467 if ((!sp->s_paused) && (!sp->s_running) &&
468 ((sp->s_head - sp->s_tail) > sp->s_fragfr)) {
469 mutex_exit(&sp->s_lock);
470 auclnt_start(sp);
471 mutex_enter(&sp->s_lock);
475 ASSERT(sp->s_tail <= sp->s_head);
476 ASSERT(sp->s_hidx < sp->s_nframes);
478 /* round off any remaining partial bits */
479 uio->uio_resid = 0;
481 mutex_exit(&sp->s_lock);
483 return (rv);
487 auclnt_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp,
488 struct pollhead **phpp)
490 audio_stream_t *sp;
491 short nev = 0;
493 if (events & (POLLIN | POLLRDNORM)) {
494 sp = &c->c_istream;
495 mutex_enter(&sp->s_lock);
496 if ((sp->s_head - sp->s_tail) > sp->s_fragfr) {
497 nev = POLLIN | POLLRDNORM;
499 mutex_exit(&sp->s_lock);
502 if (events & POLLOUT) {
503 sp = &c->c_ostream;
504 mutex_enter(&sp->s_lock);
505 if ((sp->s_nframes - (sp->s_head - sp->s_tail)) >
506 sp->s_fragfr) {
507 nev = POLLOUT;
509 mutex_exit(&sp->s_lock);
512 if (nev) {
513 *reventsp = nev & events;
514 } else {
515 *reventsp = 0;
516 if (!anyyet) {
517 *phpp = &c->c_pollhead;
520 return (0);
523 void
524 auclnt_pollwakeup(audio_client_t *c, short events)
526 pollwakeup(&c->c_pollhead, events);
529 void
530 auclnt_get_output_qlen(audio_client_t *c, uint_t *slen, uint_t *flen)
532 audio_stream_t *sp = &c->c_ostream;
533 audio_engine_t *e = sp->s_engine;
534 uint64_t el, sl;
535 uint_t cnt, er, sr;
537 if (e == NULL) {
538 /* if no output engine, can't do it! */
539 *slen = 0;
540 *flen = 0;
541 return;
544 mutex_enter(&e->e_lock);
545 mutex_enter(&sp->s_lock);
546 if (e->e_ops.audio_engine_qlen != NULL) {
547 el = ENG_QLEN(e) + (e->e_head - e->e_tail);
548 } else {
549 el = (e->e_head - e->e_tail);
551 er = e->e_rate;
552 sl = sp->s_cnv_cnt;
553 sr = sp->s_user_parms->p_rate;
554 cnt = (uint_t)(sp->s_head - sp->s_tail);
555 mutex_exit(&sp->s_lock);
556 mutex_exit(&e->e_lock);
558 /* engine frames converted to stream rate, plus stream frames */
559 *slen = cnt;
560 *flen = ((uint_t)(((el * sr) / er) + sl));
564 auclnt_set_format(audio_stream_t *sp, int fmt)
566 audio_parms_t parms;
567 int rv = 0;
570 * AC3: If we select an AC3 format, then we have to allocate
571 * another engine. Normally this will be an output only
572 * engine. However, for now we aren't supporting AC3
573 * passthru.
576 switch (fmt) {
577 case AUDIO_FORMAT_U8:
578 case AUDIO_FORMAT_ULAW:
579 case AUDIO_FORMAT_ALAW:
580 case AUDIO_FORMAT_S8:
581 case AUDIO_FORMAT_S16_LE:
582 case AUDIO_FORMAT_S16_BE:
583 case AUDIO_FORMAT_U16_LE:
584 case AUDIO_FORMAT_U16_BE:
585 case AUDIO_FORMAT_S24_LE:
586 case AUDIO_FORMAT_S24_BE:
587 case AUDIO_FORMAT_S32_LE:
588 case AUDIO_FORMAT_S32_BE:
589 case AUDIO_FORMAT_S24_PACKED:
590 break;
592 case AUDIO_FORMAT_AC3: /* AC3: PASSTHRU */
593 default:
594 return (ENOTSUP);
599 * Optimization. Some personalities send us the same format
600 * over and over again. (Sun personality does this
601 * repeatedly.) setup_src is potentially expensive, so we
602 * avoid doing it unless we really need to.
604 if (fmt != sp->s_user_parms->p_format) {
606 * Note that setting the format doesn't check that the
607 * audio streams have been paused. As a result, any
608 * data still playing or recording will probably get
609 * misinterpreted. It would be smart if the client
610 * application paused/stopped playback before changing
611 * formats.
613 parms.p_format = fmt;
614 rv = auimpl_engine_setup(sp, 0, &parms, FORMAT_MSK_FMT);
617 return (rv);
621 auclnt_get_format(audio_stream_t *sp)
623 return (sp->s_user_parms->p_format);
627 auclnt_get_output_format(audio_client_t *c)
629 return (c->c_ostream.s_user_parms->p_format);
633 auclnt_get_input_format(audio_client_t *c)
635 return (c->c_istream.s_user_parms->p_format);
639 auclnt_set_channels(audio_stream_t *sp, int nchan)
641 audio_parms_t parms;
642 int rv = 0;
644 /* Validate setting */
645 if ((nchan > AUDIO_MAX_CHANNELS) || (nchan < 1)) {
646 return (EINVAL);
649 if (nchan != sp->s_user_parms->p_nchan) {
650 parms.p_nchan = nchan;
651 rv = auimpl_engine_setup(sp, 0, &parms, FORMAT_MSK_CHAN);
654 return (rv);
658 auclnt_get_channels(audio_stream_t *sp)
660 return (sp->s_user_parms->p_nchan);
664 static void
665 auimpl_set_gain_master(audio_stream_t *sp, uint8_t gain)
667 uint32_t scaled;
669 if (gain > 100) {
670 gain = 0;
673 mutex_enter(&sp->s_lock);
674 if (sp->s_gain_master == gain) {
675 mutex_exit(&sp->s_lock);
676 return;
680 * calculate the scaled values. Done now to avoid calculations
681 * later.
683 scaled = (gain * sp->s_gain_pct * AUDIO_DB_SIZE) / (100 * 100);
685 sp->s_gain_master = gain;
686 sp->s_gain_scaled = auimpl_db_table[scaled];
688 if (!sp->s_muted) {
689 sp->s_gain_eff = sp->s_gain_scaled;
691 mutex_exit(&sp->s_lock);
695 auimpl_set_pcmvol(void *arg, uint64_t val)
697 audio_dev_t *d = arg;
698 list_t *l = &d->d_clients;
699 audio_client_t *c;
701 if (val > 100) {
702 return (EINVAL);
704 rw_enter(&auimpl_client_lock, RW_WRITER);
705 d->d_pcmvol = val & 0xff;
706 rw_downgrade(&auimpl_client_lock);
708 for (c = list_head(l); c; c = list_next(l, c)) {
709 /* don't need to check is_active here, its safe */
710 auimpl_set_gain_master(&c->c_ostream, (uint8_t)val);
712 rw_exit(&auimpl_client_lock);
714 return (0);
718 auimpl_get_pcmvol(void *arg, uint64_t *val)
720 audio_dev_t *d = arg;
722 *val = d->d_pcmvol;
723 return (0);
726 void
727 auclnt_set_gain(audio_stream_t *sp, uint8_t gain)
729 uint32_t scaled;
731 if (gain > 100) {
732 gain = 0;
735 mutex_enter(&sp->s_lock);
737 /* if no change, don't bother doing updates */
738 if (sp->s_gain_pct == gain) {
739 mutex_exit(&sp->s_lock);
740 return;
744 * calculate the scaled values. Done now to avoid calculations
745 * later.
747 scaled = (gain * sp->s_gain_master * AUDIO_DB_SIZE) / (100 * 100);
749 sp->s_gain_pct = gain;
750 sp->s_gain_scaled = auimpl_db_table[scaled];
752 if (!sp->s_muted) {
753 sp->s_gain_eff = sp->s_gain_scaled;
755 mutex_exit(&sp->s_lock);
757 atomic_inc_uint(&sp->s_client->c_dev->d_serial);
760 uint8_t
761 auclnt_get_gain(audio_stream_t *sp)
763 return (sp->s_gain_pct);
766 void
767 auclnt_set_muted(audio_stream_t *sp, boolean_t muted)
769 mutex_enter(&sp->s_lock);
771 /* if no work change, don't bother doing updates */
772 if (sp->s_muted == muted) {
773 mutex_exit(&sp->s_lock);
774 return;
777 sp->s_muted = muted;
778 if (muted) {
779 sp->s_gain_eff = 0;
780 } else {
781 sp->s_gain_eff = sp->s_gain_scaled;
783 mutex_exit(&sp->s_lock);
785 atomic_inc_uint(&sp->s_client->c_dev->d_serial);
788 boolean_t
789 auclnt_get_muted(audio_stream_t *sp)
791 return (sp->s_muted);
794 boolean_t
795 auclnt_is_running(audio_stream_t *sp)
797 return (sp->s_running);
800 void
801 auclnt_start(audio_stream_t *sp)
803 mutex_enter(&sp->s_lock);
804 sp->s_running = B_TRUE;
805 mutex_exit(&sp->s_lock);
808 void
809 auclnt_stop(audio_stream_t *sp)
811 mutex_enter(&sp->s_lock);
812 /* if running, then stop it */
813 if (sp->s_running) {
814 sp->s_running = B_FALSE;
816 * if we stopped the engine, we might need to wake up
817 * a thread that is waiting for drain to complete.
819 cv_broadcast(&sp->s_cv);
821 mutex_exit(&sp->s_lock);
825 * When pausing, no new data will be played after the most recently
826 * mixed samples have played. However, the audio engine will continue
827 * to play (possibly just silence).
829 * Note that we don't reference count the device, or release/close the
830 * engine here. Once fired up, the engine continues running unil it
831 * is closed.
833 void
834 auclnt_set_paused(audio_stream_t *sp)
836 mutex_enter(&sp->s_lock);
837 if (sp->s_paused) {
838 mutex_exit(&sp->s_lock);
839 return;
841 sp->s_paused = B_TRUE;
842 mutex_exit(&sp->s_lock);
844 auclnt_stop(sp);
846 atomic_inc_uint(&sp->s_client->c_dev->d_serial);
849 void
850 auclnt_clear_paused(audio_stream_t *sp)
852 mutex_enter(&sp->s_lock);
853 if (!sp->s_paused) {
854 mutex_exit(&sp->s_lock);
855 return;
857 sp->s_paused = B_FALSE;
858 mutex_exit(&sp->s_lock);
861 boolean_t
862 auclnt_is_paused(audio_stream_t *sp)
864 return (sp->s_paused);
867 void
868 auclnt_flush(audio_stream_t *sp)
870 mutex_enter(&sp->s_lock);
871 if (sp == &sp->s_client->c_ostream) {
872 sp->s_tail = sp->s_head;
873 sp->s_tidx = sp->s_hidx;
874 } else {
875 sp->s_head = sp->s_tail;
876 sp->s_hidx = sp->s_tidx;
878 sp->s_cnv_cnt = 0;
879 mutex_exit(&sp->s_lock);
883 auclnt_get_oflag(audio_client_t *c)
885 return (c->c_omode);
889 * These routines should not be accessed by client "personality"
890 * implementations, but are for private framework use only.
893 void
894 auimpl_client_init(void)
896 rw_init(&auimpl_client_lock, NULL, RW_DRIVER, NULL);
897 list_create(&auimpl_clients, sizeof (struct audio_client),
898 offsetof(struct audio_client, c_global_linkage));
901 void
902 auimpl_client_fini(void)
904 rw_destroy(&auimpl_client_lock);
905 list_destroy(&auimpl_clients);
908 static int
909 auimpl_stream_init(audio_stream_t *sp, audio_client_t *c)
911 mutex_init(&sp->s_lock, NULL, MUTEX_DRIVER, NULL);
912 cv_init(&sp->s_cv, NULL, CV_DRIVER, NULL);
913 sp->s_client = c;
915 if (sp == &c->c_ostream) {
916 sp->s_user_parms = &sp->s_cnv_src_parms;
917 sp->s_phys_parms = &sp->s_cnv_dst_parms;
918 sp->s_engcap = ENGINE_OUTPUT_CAP;
919 } else {
920 ASSERT(sp == &c->c_istream);
921 sp->s_user_parms = &sp->s_cnv_dst_parms;
922 sp->s_phys_parms = &sp->s_cnv_src_parms;
923 sp->s_engcap = ENGINE_INPUT_CAP;
926 /* for now initialize conversion parameters */
927 sp->s_src_quality = 3; /* reasonable compromise for now */
928 sp->s_cnv_dst_nchan = 2;
929 sp->s_cnv_dst_format = AUDIO_FORMAT_S24_NE;
930 sp->s_cnv_dst_rate = 48000;
931 sp->s_cnv_src_nchan = 2;
932 sp->s_cnv_src_format = AUDIO_FORMAT_S24_NE;
933 sp->s_cnv_src_rate = 48000;
935 /* set volume/gain all the way up */
936 sp->s_muted = B_FALSE;
937 sp->s_gain_pct = 0;
938 sp->s_gain_scaled = AUDIO_VOL_SCALE;
939 sp->s_gain_eff = AUDIO_VOL_SCALE;
942 * We have to start off with a reasonable buffer and
943 * interrupt configuration.
945 sp->s_allocsz = 65536;
946 sp->s_data = ddi_umem_alloc(sp->s_allocsz, DDI_UMEM_NOSLEEP,
947 &sp->s_cookie);
948 if (sp->s_data == NULL) {
949 sp->s_allocsz = 0;
950 audio_dev_warn(c->c_dev, "ddi_umem_alloc failed");
951 return (ENOMEM);
953 /* make sure no stale data left in stream */
954 bzero(sp->s_data, sp->s_allocsz);
957 * Allocate SRC and data conversion state.
959 mutex_enter(&sp->s_lock);
960 if (auimpl_format_alloc(sp) != 0) {
961 mutex_exit(&sp->s_lock);
962 return (ENOMEM);
965 mutex_exit(&sp->s_lock);
967 return (0);
971 static void
972 audio_stream_fini(audio_stream_t *sp)
974 auimpl_format_free(sp);
975 if (sp->s_cnv_buf0)
976 kmem_free(sp->s_cnv_buf0, sp->s_cnv_max);
977 if (sp->s_cnv_buf1)
978 kmem_free(sp->s_cnv_buf1, sp->s_cnv_max);
979 mutex_destroy(&sp->s_lock);
980 cv_destroy(&sp->s_cv);
981 if (sp->s_data != NULL) {
982 ddi_umem_free(sp->s_cookie);
983 sp->s_data = NULL;
988 auclnt_start_drain(audio_client_t *c)
990 audio_stream_t *sp;
991 int rv;
993 sp = &c->c_ostream;
995 /* start an asynchronous drain operation. */
996 mutex_enter(&sp->s_lock);
997 if (sp->s_paused || !sp->s_running) {
998 rv = EALREADY;
999 } else {
1000 sp->s_draining = B_TRUE;
1001 rv = 0;
1003 mutex_exit(&sp->s_lock);
1004 return (rv);
1008 auclnt_drain(audio_client_t *c)
1010 audio_stream_t *sp;
1012 sp = &c->c_ostream;
1015 * Note: Drain logic will automatically "stop" the stream when
1016 * the drain threshold has been reached. So all we have to do
1017 * is wait for the stream to stop.
1019 mutex_enter(&sp->s_lock);
1020 sp->s_draining = B_TRUE;
1021 while (sp->s_draining && sp->s_running && !sp->s_paused) {
1022 if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
1023 mutex_exit(&sp->s_lock);
1024 return (EINTR);
1027 mutex_exit(&sp->s_lock);
1028 return (0);
1031 audio_client_t *
1032 auimpl_client_create(dev_t dev)
1034 audio_client_ops_t *ops;
1035 audio_client_t *c;
1036 audio_client_t *next;
1037 list_t *list = &auimpl_clients;
1038 minor_t minor;
1039 audio_dev_t *d;
1041 /* validate minor number */
1042 minor = getminor(dev) & AUDIO_MN_TYPE_MASK;
1043 if ((ops = audio_client_ops[minor]) == NULL) {
1044 return (NULL);
1047 /* lookup device instance */
1048 if ((d = auimpl_dev_hold_by_devt(dev)) == NULL) {
1049 audio_dev_warn(NULL, "no audio_dev for dev_t %d,%d",
1050 getmajor(dev), getminor(dev));
1051 return (NULL);
1054 if ((c = kmem_zalloc(sizeof (*c), KM_NOSLEEP)) == NULL) {
1055 audio_dev_warn(d, "unable to allocate client structure");
1056 auimpl_dev_release(d);
1057 return (NULL);
1059 c->c_dev = d;
1061 mutex_init(&c->c_lock, NULL, MUTEX_DRIVER, NULL);
1062 cv_init(&c->c_cv, NULL, CV_DRIVER, NULL);
1064 if ((auimpl_stream_init(&c->c_ostream, c) != 0) ||
1065 (auimpl_stream_init(&c->c_istream, c) != 0)) {
1066 goto failed;
1069 c->c_major = getmajor(dev);
1070 c->c_origminor = getminor(dev);
1071 c->c_ops = *ops;
1074 * We hold the client lock here.
1076 rw_enter(&auimpl_client_lock, RW_WRITER);
1078 minor = AUDIO_MN_CLONE_MASK;
1079 for (next = list_head(list); next; next = list_next(list, next)) {
1080 if (next->c_minor > minor) {
1081 break;
1083 minor++;
1085 if (minor >= MAXMIN32) {
1086 rw_exit(&auimpl_client_lock);
1087 goto failed;
1089 c->c_minor = minor;
1090 list_insert_before(list, next, c);
1092 rw_exit(&auimpl_client_lock);
1095 return (c);
1097 failed:
1098 auimpl_dev_release(d);
1099 audio_stream_fini(&c->c_ostream);
1100 audio_stream_fini(&c->c_istream);
1101 mutex_destroy(&c->c_lock);
1102 cv_destroy(&c->c_cv);
1103 kmem_free(c, sizeof (*c));
1104 return (NULL);
1107 void
1108 auimpl_client_destroy(audio_client_t *c)
1110 /* remove us from the global list */
1111 rw_enter(&auimpl_client_lock, RW_WRITER);
1112 list_remove(&auimpl_clients, c);
1113 rw_exit(&auimpl_client_lock);
1115 ASSERT(!c->c_istream.s_running);
1116 ASSERT(!c->c_ostream.s_running);
1118 /* release the device reference count */
1119 auimpl_dev_release(c->c_dev);
1120 c->c_dev = NULL;
1122 mutex_destroy(&c->c_lock);
1123 cv_destroy(&c->c_cv);
1125 audio_stream_fini(&c->c_istream);
1126 audio_stream_fini(&c->c_ostream);
1127 kmem_free(c, sizeof (*c));
1130 void
1131 auimpl_client_activate(audio_client_t *c)
1133 rw_enter(&auimpl_client_lock, RW_WRITER);
1134 c->c_is_active = B_TRUE;
1135 rw_exit(&auimpl_client_lock);
1138 void
1139 auimpl_client_deactivate(audio_client_t *c)
1141 rw_enter(&auimpl_client_lock, RW_WRITER);
1142 c->c_is_active = B_FALSE;
1143 rw_exit(&auimpl_client_lock);
1146 void
1147 auclnt_close(audio_client_t *c)
1149 audio_dev_t *d = c->c_dev;
1151 /* stop the engines if they are running */
1152 auclnt_stop(&c->c_istream);
1153 auclnt_stop(&c->c_ostream);
1155 rw_enter(&auimpl_client_lock, RW_WRITER);
1156 list_remove(&d->d_clients, c);
1157 rw_exit(&auimpl_client_lock);
1159 mutex_enter(&c->c_lock);
1160 /* if in transition need to wait for other thread to release */
1161 while (c->c_refcnt) {
1162 cv_wait(&c->c_cv, &c->c_lock);
1164 mutex_exit(&c->c_lock);
1166 /* release any engines that we were holding */
1167 auimpl_engine_close(&c->c_ostream);
1168 auimpl_engine_close(&c->c_istream);
1171 audio_dev_t *
1172 auclnt_hold_dev_by_index(int index)
1174 return (auimpl_dev_hold_by_index(index));
1177 void
1178 auclnt_release_dev(audio_dev_t *dev)
1180 auimpl_dev_release(dev);
1183 audio_client_t *
1184 auclnt_hold_by_devt(dev_t dev)
1186 minor_t mn = getminor(dev);
1187 major_t mj = getmajor(dev);
1188 list_t *list;
1189 audio_client_t *c;
1191 list = &auimpl_clients;
1192 /* linked list search is kind of inefficient, but it works */
1193 rw_enter(&auimpl_client_lock, RW_READER);
1194 for (c = list_head(list); c != NULL; c = list_next(list, c)) {
1195 if ((c->c_major == mj) && (c->c_minor == mn)) {
1196 mutex_enter(&c->c_lock);
1197 if (c->c_is_active) {
1198 c->c_refcnt++;
1199 mutex_exit(&c->c_lock);
1200 } else {
1201 mutex_exit(&c->c_lock);
1202 c = NULL;
1204 break;
1207 rw_exit(&auimpl_client_lock);
1208 return (c);
1212 auclnt_serialize(audio_client_t *c)
1214 mutex_enter(&c->c_lock);
1215 while (c->c_serialize) {
1216 if (cv_wait_sig(&c->c_cv, &c->c_lock) == 0) {
1217 mutex_exit(&c->c_lock);
1218 return (EINTR);
1221 c->c_serialize = B_TRUE;
1222 mutex_exit(&c->c_lock);
1223 return (0);
1226 void
1227 auclnt_unserialize(audio_client_t *c)
1229 mutex_enter(&c->c_lock);
1230 ASSERT(c->c_serialize);
1231 c->c_serialize = B_FALSE;
1232 cv_broadcast(&c->c_cv);
1233 mutex_exit(&c->c_lock);
1236 void
1237 auclnt_hold(audio_client_t *c)
1239 mutex_enter(&c->c_lock);
1240 c->c_refcnt++;
1241 mutex_exit(&c->c_lock);
1244 void
1245 auclnt_release(audio_client_t *c)
1247 mutex_enter(&c->c_lock);
1248 ASSERT(c->c_refcnt > 0);
1249 c->c_refcnt--;
1250 if (c->c_refcnt == 0)
1251 cv_broadcast(&c->c_cv);
1252 mutex_exit(&c->c_lock);
1255 uint_t
1256 auclnt_dev_get_serial(audio_dev_t *d)
1258 return (d->d_serial);
1261 void
1262 auclnt_dev_walk_clients(audio_dev_t *d,
1263 int (*walker)(audio_client_t *, void *),
1264 void *arg)
1266 list_t *l = &d->d_clients;
1267 audio_client_t *c;
1268 int rv;
1270 rw_enter(&auimpl_client_lock, RW_READER);
1271 restart:
1272 for (c = list_head(l); c != NULL; c = list_next(l, c)) {
1273 if (!c->c_is_active)
1274 continue;
1275 rv = (walker(c, arg));
1276 if (rv == AUDIO_WALK_STOP) {
1277 break;
1278 } else if (rv == AUDIO_WALK_RESTART) {
1279 goto restart;
1282 rw_exit(&auimpl_client_lock);
1287 auclnt_open(audio_client_t *c, int oflag)
1289 audio_stream_t *sp;
1290 audio_dev_t *d = c->c_dev;
1291 int rv = 0;
1292 int flags;
1294 flags = 0;
1295 if (oflag & FNDELAY)
1296 flags |= ENGINE_NDELAY;
1298 if (oflag & FWRITE) {
1299 sp = &c->c_ostream;
1300 if ((rv = auimpl_engine_open(sp, flags | ENGINE_OUTPUT)) != 0)
1301 goto done;
1304 if (oflag & FREAD) {
1305 sp = &c->c_istream;
1306 if ((rv = auimpl_engine_open(sp, flags | ENGINE_INPUT)) != 0)
1307 goto done;
1310 done:
1311 if (rv != 0) {
1312 /* close any engines that we opened */
1313 auimpl_engine_close(&c->c_ostream);
1314 auimpl_engine_close(&c->c_istream);
1315 } else {
1316 rw_enter(&auimpl_client_lock, RW_WRITER);
1317 list_insert_tail(&d->d_clients, c);
1318 c->c_ostream.s_gain_master = d->d_pcmvol;
1319 c->c_istream.s_gain_master = 100;
1320 rw_exit(&auimpl_client_lock);
1321 auclnt_set_gain(&c->c_ostream, 100);
1322 auclnt_set_gain(&c->c_istream, 100);
1325 return (rv);
1328 minor_t
1329 auclnt_get_minor(audio_client_t *c)
1331 return (c->c_minor);
1334 minor_t
1335 auclnt_get_original_minor(audio_client_t *c)
1337 return (c->c_origminor);
1340 minor_t
1341 auclnt_get_minor_type(audio_client_t *c)
1343 return (c->c_origminor & AUDIO_MN_TYPE_MASK);
1346 queue_t *
1347 auclnt_get_rq(audio_client_t *c)
1349 return (c->c_rq);
1352 queue_t *
1353 auclnt_get_wq(audio_client_t *c)
1355 return (c->c_wq);
1358 pid_t
1359 auclnt_get_pid(audio_client_t *c)
1361 return (c->c_pid);
1364 cred_t *
1365 auclnt_get_cred(audio_client_t *c)
1367 return (c->c_cred);
1370 audio_dev_t *
1371 auclnt_get_dev(audio_client_t *c)
1373 return (c->c_dev);
1377 auclnt_get_dev_number(audio_dev_t *dev)
1379 return (dev->d_number);
1383 auclnt_get_dev_index(audio_dev_t *dev)
1385 return (dev->d_index);
1388 const char *
1389 auclnt_get_dev_name(audio_dev_t *dev)
1391 return (dev->d_name);
1394 const char *
1395 auclnt_get_dev_driver(audio_dev_t *dev)
1397 return (ddi_driver_name(dev->d_dip));
1400 dev_info_t *
1401 auclnt_get_dev_devinfo(audio_dev_t *dev)
1403 return (dev->d_dip);
1406 const char *
1407 auclnt_get_dev_hw_info(audio_dev_t *dev, void **iter)
1409 struct audio_infostr *isp = *iter;
1410 if (isp == NULL) {
1411 isp = list_head(&dev->d_hwinfo);
1412 } else {
1413 isp = list_next(&dev->d_hwinfo, isp);
1416 *iter = isp;
1417 return (isp ? isp->i_line : NULL);
1421 auclnt_get_dev_instance(audio_dev_t *dev)
1423 return (dev->d_instance);
1426 const char *
1427 auclnt_get_dev_description(audio_dev_t *dev)
1429 return (dev->d_desc);
1432 const char *
1433 auclnt_get_dev_version(audio_dev_t *dev)
1435 return (dev->d_vers);
1438 uint_t
1439 auclnt_get_dev_capab(audio_dev_t *dev)
1441 uint32_t flags;
1442 uint_t caps = 0;
1444 flags = dev->d_flags;
1446 if (flags & DEV_OUTPUT_CAP)
1447 caps |= AUDIO_CLIENT_CAP_PLAY;
1448 if (flags & DEV_INPUT_CAP)
1449 caps |= AUDIO_CLIENT_CAP_RECORD;
1450 if (flags & DEV_DUPLEX_CAP)
1451 caps |= AUDIO_CLIENT_CAP_DUPLEX;
1453 /* AC3: deal with formats that don't support mixing */
1455 return (caps);
1458 uint64_t
1459 auclnt_get_samples(audio_stream_t *sp)
1461 uint64_t n;
1463 mutex_enter(&sp->s_lock);
1464 n = sp->s_samples;
1465 mutex_exit(&sp->s_lock);
1466 return (n);
1469 void
1470 auclnt_set_samples(audio_stream_t *sp, uint64_t n)
1472 mutex_enter(&sp->s_lock);
1473 sp->s_samples = n;
1474 mutex_exit(&sp->s_lock);
1477 uint64_t
1478 auclnt_get_errors(audio_stream_t *sp)
1480 uint64_t n;
1481 mutex_enter(&sp->s_lock);
1482 n = sp->s_errors;
1483 mutex_exit(&sp->s_lock);
1484 return (n);
1487 void
1488 auclnt_set_errors(audio_stream_t *sp, uint64_t n)
1490 mutex_enter(&sp->s_lock);
1491 sp->s_errors = n;
1492 mutex_exit(&sp->s_lock);
1495 void
1496 auclnt_register_ops(minor_t minor, audio_client_ops_t *ops)
1498 /* we control minor number allocations, no need for runtime checks */
1499 ASSERT(minor <= AUDIO_MN_TYPE_MASK);
1501 audio_client_ops[minor] = ops;
1505 auimpl_create_minors(audio_dev_t *d)
1507 char path[MAXPATHLEN];
1508 int rv = 0;
1509 minor_t minor;
1510 audio_client_ops_t *ops;
1511 char *nt;
1513 for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) {
1515 if ((ops = audio_client_ops[i]) == NULL)
1516 continue;
1518 if (ops->aco_dev_init != NULL)
1519 d->d_minor_data[i] = ops->aco_dev_init(d);
1521 switch (i) {
1522 case AUDIO_MINOR_SNDSTAT:
1523 if (!(d->d_flags & DEV_SNDSTAT_CAP)) {
1524 continue;
1526 nt = DDI_PSEUDO;
1527 break;
1529 default:
1530 if (!(d->d_flags & (DEV_INPUT_CAP| DEV_OUTPUT_CAP))) {
1531 continue;
1533 nt = DDI_NT_AUDIO;
1534 break;
1537 if (ops->aco_minor_prefix != NULL) {
1539 minor = AUDIO_MKMN(d->d_instance, i);
1540 (void) snprintf(path, sizeof (path),
1541 "%s%d", ops->aco_minor_prefix, d->d_instance);
1543 rv = ddi_create_minor_node(d->d_dip, path, S_IFCHR,
1544 minor, nt, 0);
1546 if (rv != 0)
1547 break;
1550 return (rv);
1553 void
1554 auimpl_remove_minors(audio_dev_t *d)
1556 char path[MAXPATHLEN];
1557 audio_client_ops_t *ops;
1559 for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) {
1560 if ((ops = audio_client_ops[i]) == NULL)
1561 continue;
1562 if (ops->aco_minor_prefix != NULL) {
1563 (void) snprintf(path, sizeof (path), "%s%d",
1564 ops->aco_minor_prefix, d->d_instance);
1565 (void) ddi_remove_minor_node(d->d_dip, path);
1568 if (ops->aco_dev_fini != NULL)
1569 ops->aco_dev_fini(d->d_minor_data[i]);
1573 void *
1574 auclnt_get_dev_minor_data(audio_dev_t *d, minor_t mn)
1576 ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS));
1577 return (d->d_minor_data[mn]);
1580 void *
1581 auclnt_get_minor_data(audio_client_t *c, minor_t mn)
1583 ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS));
1584 return (c->c_dev->d_minor_data[mn]);
1588 * This will walk all controls registered to a clients device and callback
1589 * to walker for each one with its audio_ctrl. Note this data
1590 * must be considered read only by walker.
1592 * Note that walk_func may return values to continue (AUDIO_WALK_CONTINUE)
1593 * or stop walk (AUDIO_WALK_STOP).
1596 void
1597 auclnt_walk_controls(audio_dev_t *d,
1598 int (*walker)(audio_ctrl_t *, void *),
1599 void *arg)
1601 audio_ctrl_t *ctrl;
1603 mutex_enter(&d->d_ctrl_lock);
1604 for (ctrl = list_head(&d->d_controls); ctrl;
1605 ctrl = list_next(&d->d_controls, ctrl)) {
1606 if (walker(ctrl, arg) == AUDIO_WALK_STOP)
1607 break;
1609 mutex_exit(&d->d_ctrl_lock);
1613 * This will search all controls attached to an
1614 * audio device for a control with the desired name.
1616 * d - the audio device to look on
1617 * name - name of the control being looked for.
1619 * On successful return a ctrl handle will be returned. On
1620 * failure NULL is returned.
1622 audio_ctrl_t *
1623 auclnt_find_control(audio_dev_t *d, const char *name)
1625 audio_ctrl_t *ctrl;
1627 /* Verify argument */
1628 ASSERT(d);
1630 mutex_enter(&d->d_ctrl_lock);
1631 for (ctrl = list_head(&d->d_controls); ctrl;
1632 ctrl = list_next(&d->d_controls, ctrl)) {
1633 if (strcmp(ctrl->ctrl_name, name) == 0) {
1634 mutex_exit(&d->d_ctrl_lock);
1635 return (ctrl);
1638 mutex_exit(&d->d_ctrl_lock);
1639 return (NULL);
1643 * Given a known control, get its attributes.
1645 * The caller must supply a audio_ctrl_desc_t structure. Also the
1646 * values in the structure are ignored when making the call and filled
1647 * in by this function. All data pointed to by elements of desc should
1648 * be assumed read only.
1650 * If an error occurs then a non-zero is returned.
1654 auclnt_control_describe(audio_ctrl_t *ctrl, audio_ctrl_desc_t *desc)
1656 ASSERT(ctrl);
1657 ASSERT(desc);
1659 bcopy(&ctrl->ctrl_des, desc, sizeof (*desc));
1660 return (0);
1664 auclnt_control_read(audio_ctrl_t *ctrl, uint64_t *value)
1666 return (audio_control_read(ctrl, value));
1670 auclnt_control_write(audio_ctrl_t *ctrl, uint64_t value)
1672 return (audio_control_write(ctrl, value));
1675 void
1676 auclnt_warn(audio_client_t *c, const char *fmt, ...)
1678 va_list va;
1680 va_start(va, fmt);
1681 auimpl_dev_vwarn(c ? c->c_dev : NULL, fmt, va);
1682 va_end(va);