6863438 AUDIO_GETINFO always returns a non-0 'play.active' value
[unleashed.git] / usr / src / uts / common / io / audio / impl / audio_client.c
blobe6c354ae149f8752070ee4aa20728e156404c894
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 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 #include <sys/types.h>
29 #include <sys/sysmacros.h>
30 #include <sys/list.h>
31 #include <sys/file.h>
32 #include <sys/open.h>
33 #include <sys/stat.h>
34 #include <sys/errno.h>
35 #include <sys/atomic.h>
36 #include <sys/ddi.h>
37 #include <sys/sunddi.h>
39 #include "audio_impl.h"
42 * Audio Client implementation.
46 * Attenuation table for dB->linear conversion. Indexed in steps of
47 * 0.5 dB. Table size is 25 dB (first entry is handled as mute).
49 * Notably, the last item in table is taken as 0 dB (i.e. maximum volume).
51 * Table contents can be calculated as follows (requires sunmath library):
53 * scale = AUDIO_VOL_SCALE;
54 * for (i = -50; i <= 0; i++) {
55 * x = exp10(0.05 * i);
56 * printf("%d: %f %.0f\n", i, x, trunc(x * scale));
57 * }
61 const uint16_t auimpl_db_table[AUDIO_DB_SIZE + 1] = {
62 0, 0, 1, 1, 1, 1, 1, 1, 2, 2,
63 2, 2, 3, 3, 4, 4, 5, 5, 6, 7,
64 8, 9, 10, 11, 12, 14, 16, 18, 20, 22,
65 25, 28, 32, 36, 40, 45, 51, 57, 64, 72,
66 80, 90, 101, 114, 128, 143, 161, 181, 203, 228,
67 256
70 void *
71 auclnt_get_private(audio_client_t *c)
73 return (c->c_private);
76 void
77 auclnt_set_private(audio_client_t *c, void *private)
79 c->c_private = private;
82 int
83 auclnt_set_rate(audio_stream_t *sp, int rate)
85 audio_parms_t parms;
86 int rv = 0;
88 /* basic sanity checks! */
89 if ((rate < 5000) || (rate > 192000)) {
90 return (EINVAL);
92 mutex_enter(&sp->s_lock);
93 parms = *sp->s_user_parms;
94 if (rate != parms.p_rate) {
95 parms.p_rate = rate;
96 rv = auimpl_format_setup(sp, &parms);
98 mutex_exit(&sp->s_lock);
99 return (rv);
103 auclnt_get_rate(audio_stream_t *sp)
105 return (sp->s_user_parms->p_rate);
108 unsigned
109 auclnt_get_fragsz(audio_stream_t *sp)
111 return (sp->s_fragbytes);
114 unsigned
115 auclnt_get_framesz(audio_stream_t *sp)
117 return (sp->s_framesz);
120 unsigned
121 auclnt_get_nfrags(audio_stream_t *sp)
123 return (sp->s_nfrags);
126 unsigned
127 auclnt_get_nframes(audio_stream_t *sp)
129 return (sp->s_nframes);
132 void
133 auclnt_set_latency(audio_stream_t *sp, unsigned frags, unsigned 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 unsigned
154 auclnt_get_hidx(audio_stream_t *sp)
156 return (sp->s_hidx);
159 unsigned
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 unsigned
178 auclnt_get_count(audio_stream_t *sp)
180 unsigned count;
182 mutex_enter(&sp->s_lock);
183 ASSERT((sp->s_head - sp->s_tail) <= sp->s_nframes);
184 count = (unsigned)(sp->s_head - sp->s_tail);
185 mutex_exit(&sp->s_lock);
187 return (count);
190 unsigned
191 auclnt_consume(audio_stream_t *sp, unsigned 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 unsigned
212 auclnt_consume_data(audio_stream_t *sp, caddr_t dst, unsigned n)
214 unsigned nframes;
215 unsigned framesz;
216 unsigned 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 unsigned 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 unsigned
259 auclnt_produce(audio_stream_t *sp, unsigned 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 unsigned
280 auclnt_produce_data(audio_stream_t *sp, caddr_t src, unsigned n)
282 unsigned nframes;
283 unsigned framesz;
284 unsigned 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 unsigned 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 unsigned cnt;
332 int rv = 0;
333 offset_t loff;
334 int eagain;
336 loff = uio->uio_loffset;
337 eagain = EAGAIN;
339 mutex_enter(&sp->s_lock);
341 if ((!sp->s_paused) && (!sp->s_running)) {
342 mutex_exit(&sp->s_lock);
343 auclnt_start(sp);
344 mutex_enter(&sp->s_lock);
347 ASSERT(sp->s_head >= sp->s_tail);
348 ASSERT(sp->s_tidx < sp->s_nframes);
349 ASSERT(sp->s_hidx < sp->s_nframes);
351 while (uio->uio_resid >= sp->s_framesz) {
353 while ((cnt = (sp->s_head - sp->s_tail)) == 0) {
354 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
355 mutex_exit(&sp->s_lock);
356 return (eagain);
358 if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
359 mutex_exit(&sp->s_lock);
360 return (EINTR);
364 cnt = min(cnt, sp->s_nframes - sp->s_tidx);
365 cnt = min(cnt, (uio->uio_resid / sp->s_framesz));
367 rv = uiomove(sp->s_data + (sp->s_tidx * sp->s_framesz),
368 cnt * sp->s_framesz, UIO_READ, uio);
369 uio->uio_loffset = loff;
370 eagain = 0;
372 if (rv != 0) {
373 mutex_exit(&sp->s_lock);
374 return (rv);
377 sp->s_tail += cnt;
378 sp->s_tidx += cnt;
379 if (sp->s_tidx == sp->s_nframes) {
380 sp->s_tidx = 0;
384 ASSERT(sp->s_tail <= sp->s_head);
385 ASSERT(sp->s_tidx < sp->s_nframes);
387 /* round off any remaining partial bits */
388 uio->uio_resid = 0;
390 mutex_exit(&sp->s_lock);
392 return (rv);
396 auclnt_write(audio_client_t *c, struct uio *uio)
398 audio_stream_t *sp = &c->c_ostream;
399 unsigned cnt;
400 int rv = 0;
401 offset_t loff;
402 int eagain;
404 loff = uio->uio_loffset;
405 eagain = EAGAIN;
407 mutex_enter(&sp->s_lock);
409 ASSERT(sp->s_head >= sp->s_tail);
410 ASSERT(sp->s_tidx < sp->s_nframes);
411 ASSERT(sp->s_hidx < sp->s_nframes);
413 while (uio->uio_resid >= sp->s_framesz) {
415 while ((cnt = sp->s_nframes - (sp->s_head - sp->s_tail)) == 0) {
416 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) {
417 mutex_exit(&sp->s_lock);
418 return (eagain);
420 if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
421 mutex_exit(&sp->s_lock);
422 return (EINTR);
426 cnt = min(cnt, sp->s_nframes - sp->s_hidx);
427 cnt = min(cnt, (uio->uio_resid / sp->s_framesz));
429 rv = uiomove(sp->s_data + (sp->s_hidx * sp->s_framesz),
430 cnt * sp->s_framesz, UIO_WRITE, uio);
431 uio->uio_loffset = loff;
432 eagain = 0;
434 if (rv != 0) {
435 mutex_exit(&sp->s_lock);
436 return (rv);
439 sp->s_head += cnt;
440 sp->s_hidx += cnt;
441 if (sp->s_hidx == sp->s_nframes) {
442 sp->s_hidx = 0;
445 if ((!sp->s_paused) && (!sp->s_running) &&
446 ((sp->s_head - sp->s_tail) > sp->s_fragfr)) {
447 mutex_exit(&sp->s_lock);
448 auclnt_start(sp);
449 mutex_enter(&sp->s_lock);
453 ASSERT(sp->s_tail <= sp->s_head);
454 ASSERT(sp->s_hidx < sp->s_nframes);
456 /* round off any remaining partial bits */
457 uio->uio_resid = 0;
459 mutex_exit(&sp->s_lock);
461 return (rv);
465 auclnt_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp,
466 struct pollhead **phpp)
468 audio_stream_t *sp;
469 short nev = 0;
471 if (events & (POLLIN | POLLRDNORM)) {
472 sp = &c->c_istream;
473 mutex_enter(&sp->s_lock);
474 if ((sp->s_head - sp->s_tail) > sp->s_fragfr) {
475 nev = POLLIN | POLLRDNORM;
477 mutex_exit(&sp->s_lock);
480 if (events & POLLOUT) {
481 sp = &c->c_ostream;
482 mutex_enter(&sp->s_lock);
483 if ((sp->s_nframes - (sp->s_head - sp->s_tail)) >
484 sp->s_fragfr) {
485 nev = POLLOUT;
487 mutex_exit(&sp->s_lock);
490 if (nev) {
491 *reventsp = nev & events;
492 } else {
493 *reventsp = 0;
494 if (!anyyet) {
495 *phpp = &c->c_pollhead;
498 return (0);
501 void
502 auclnt_pollwakeup(audio_client_t *c, short events)
504 pollwakeup(&c->c_pollhead, events);
507 void
508 auclnt_get_output_qlen(audio_client_t *c, unsigned *slen, unsigned *flen)
510 audio_stream_t *sp = &c->c_ostream;
511 audio_engine_t *e = sp->s_engine;
512 uint64_t el, sl;
513 unsigned cnt, er, sr;
515 if (e == NULL) {
516 /* if no output engine, can't do it! */
517 *slen = 0;
518 *flen = 0;
519 return;
522 mutex_enter(&e->e_lock);
523 mutex_enter(&sp->s_lock);
524 el = ENG_QLEN(e) + (e->e_head - e->e_tail);
525 er = e->e_rate;
526 sl = sp->s_cnv_cnt;
527 sr = sp->s_user_parms->p_rate;
528 cnt = (unsigned)(sp->s_head - sp->s_tail);
529 mutex_exit(&sp->s_lock);
530 mutex_exit(&e->e_lock);
532 /* engine frames converted to stream rate, plus stream frames */
533 *slen = cnt;
534 *flen = ((unsigned)(((el * sr) / er) + sl));
538 auclnt_set_format(audio_stream_t *sp, int fmt)
540 audio_parms_t parms;
541 int rv = 0;
544 * AC3: If we select an AC3 format, then we have to allocate
545 * another engine. Normally this will be an output only
546 * engine. However, for now we aren't supporting AC3
547 * passthru.
550 switch (fmt) {
551 case AUDIO_FORMAT_U8:
552 case AUDIO_FORMAT_ULAW:
553 case AUDIO_FORMAT_ALAW:
554 case AUDIO_FORMAT_S8:
555 case AUDIO_FORMAT_S16_LE:
556 case AUDIO_FORMAT_S16_BE:
557 case AUDIO_FORMAT_U16_LE:
558 case AUDIO_FORMAT_U16_BE:
559 case AUDIO_FORMAT_S24_LE:
560 case AUDIO_FORMAT_S24_BE:
561 case AUDIO_FORMAT_S32_LE:
562 case AUDIO_FORMAT_S32_BE:
563 case AUDIO_FORMAT_S24_PACKED:
564 break;
566 case AUDIO_FORMAT_AC3: /* AC3: PASSTHRU */
567 default:
568 return (ENOTSUP);
572 mutex_enter(&sp->s_lock);
573 parms = *sp->s_user_parms;
576 * Optimization. Some personalities send us the same format
577 * over and over again. (Sun personality does this
578 * repeatedly.) setup_src is potentially expensive, so we
579 * avoid doing it unless we really need to.
581 if (fmt != parms.p_format) {
583 * Note that setting the format doesn't check that the
584 * audio streams have been paused. As a result, any
585 * data still playing or recording will probably get
586 * misinterpreted. It would be smart if the client
587 * application paused/stopped playback before changing
588 * formats.
590 parms.p_format = fmt;
591 rv = auimpl_format_setup(sp, &parms);
593 mutex_exit(&sp->s_lock);
595 return (rv);
599 auclnt_get_format(audio_stream_t *sp)
601 return (sp->s_user_parms->p_format);
605 auclnt_get_output_format(audio_client_t *c)
607 return (c->c_ostream.s_user_parms->p_format);
611 auclnt_get_input_format(audio_client_t *c)
613 return (c->c_istream.s_user_parms->p_format);
617 auclnt_set_channels(audio_stream_t *sp, int nchan)
619 audio_parms_t parms;
620 int rv = 0;
622 /* Validate setting */
623 if ((nchan > AUDIO_MAX_CHANNELS) || (nchan < 1)) {
624 return (EINVAL);
627 mutex_enter(&sp->s_lock);
628 parms = *sp->s_user_parms;
629 if (nchan != parms.p_nchan) {
630 parms.p_nchan = nchan;
631 rv = auimpl_format_setup(sp, &parms);
633 mutex_exit(&sp->s_lock);
635 return (rv);
639 auclnt_get_channels(audio_stream_t *sp)
641 return (sp->s_user_parms->p_nchan);
644 void
645 auimpl_set_gain_master(audio_stream_t *sp, uint8_t gain)
647 uint32_t scaled;
649 if (gain > 100) {
650 gain = 0;
653 mutex_enter(&sp->s_lock);
654 if (sp->s_gain_master == gain) {
655 mutex_exit(&sp->s_lock);
656 return;
660 * calculate the scaled values. Done now to avoid calculations
661 * later.
663 scaled = (gain * sp->s_gain_pct * AUDIO_DB_SIZE) / (100 * 100);
665 sp->s_gain_master = gain;
666 sp->s_gain_scaled = auimpl_db_table[scaled];
668 if (!sp->s_muted) {
669 sp->s_gain_eff = sp->s_gain_scaled;
671 mutex_exit(&sp->s_lock);
674 * No need to notify clients, since they can't see this update.
678 void
679 auclnt_set_gain(audio_stream_t *sp, uint8_t gain)
681 uint32_t scaled;
683 if (gain > 100) {
684 gain = 0;
687 mutex_enter(&sp->s_lock);
689 /* if no change, don't bother doing updates */
690 if (sp->s_gain_pct == gain) {
691 mutex_exit(&sp->s_lock);
692 return;
696 * calculate the scaled values. Done now to avoid calculations
697 * later.
699 scaled = (gain * sp->s_gain_master * AUDIO_DB_SIZE) / (100 * 100);
701 sp->s_gain_pct = gain;
702 sp->s_gain_scaled = auimpl_db_table[scaled];
704 if (!sp->s_muted) {
705 sp->s_gain_eff = sp->s_gain_scaled;
707 mutex_exit(&sp->s_lock);
709 auclnt_notify_dev(sp->s_client->c_dev);
712 uint8_t
713 auclnt_get_gain(audio_stream_t *sp)
715 return (sp->s_gain_pct);
718 void
719 auclnt_set_muted(audio_stream_t *sp, boolean_t muted)
721 mutex_enter(&sp->s_lock);
723 /* if no work change, don't bother doing updates */
724 if (sp->s_muted == muted) {
725 mutex_exit(&sp->s_lock);
726 return;
729 sp->s_muted = muted;
730 if (muted) {
731 sp->s_gain_eff = 0;
732 } else {
733 sp->s_gain_eff = sp->s_gain_scaled;
735 mutex_exit(&sp->s_lock);
737 auclnt_notify_dev(sp->s_client->c_dev);
740 boolean_t
741 auclnt_get_muted(audio_stream_t *sp)
743 return (sp->s_muted);
746 boolean_t
747 auclnt_is_running(audio_stream_t *sp)
749 return (sp->s_running);
752 void
753 auclnt_start(audio_stream_t *sp)
755 mutex_enter(&sp->s_lock);
756 sp->s_running = B_TRUE;
757 mutex_exit(&sp->s_lock);
760 void
761 auclnt_stop(audio_stream_t *sp)
763 mutex_enter(&sp->s_lock);
764 /* if running, then stop it */
765 if (sp->s_running) {
766 sp->s_running = B_FALSE;
768 * if we stopped the engine, we might need to wake up
769 * a thread that is waiting for drain to complete.
771 cv_broadcast(&sp->s_cv);
773 mutex_exit(&sp->s_lock);
777 * When pausing, no new data will be played after the most recently
778 * mixed samples have played. However, the audio engine will continue
779 * to play (possibly just silence).
781 * Note that we don't reference count the device, or release/close the
782 * engine here. Once fired up, the engine continues running unil it
783 * is closed.
785 void
786 auclnt_set_paused(audio_stream_t *sp)
788 mutex_enter(&sp->s_lock);
789 if (sp->s_paused) {
790 mutex_exit(&sp->s_lock);
791 return;
793 sp->s_paused = B_TRUE;
794 mutex_exit(&sp->s_lock);
796 auclnt_stop(sp);
798 auclnt_notify_dev(sp->s_client->c_dev);
801 void
802 auclnt_clear_paused(audio_stream_t *sp)
804 mutex_enter(&sp->s_lock);
805 if (!sp->s_paused) {
806 mutex_exit(&sp->s_lock);
807 return;
809 sp->s_paused = B_FALSE;
810 mutex_exit(&sp->s_lock);
813 boolean_t
814 auclnt_is_paused(audio_stream_t *sp)
816 return (sp->s_paused);
819 void
820 auclnt_flush(audio_stream_t *sp)
822 mutex_enter(&sp->s_lock);
823 if (sp == &sp->s_client->c_ostream) {
824 sp->s_tail = sp->s_head;
825 sp->s_tidx = sp->s_hidx;
826 } else {
827 sp->s_head = sp->s_tail;
828 sp->s_hidx = sp->s_tidx;
830 sp->s_cnv_cnt = 0;
831 mutex_exit(&sp->s_lock);
835 auclnt_get_oflag(audio_client_t *c)
837 return (c->c_omode);
841 * These routines should not be accessed by client "personality"
842 * implementations, but are for private framework use only.
845 static list_t auimpl_clients;
846 static krwlock_t auimpl_client_lock;
847 static audio_client_ops_t *audio_client_ops[AUDIO_MN_TYPE_MASK + 1];
849 void
850 auimpl_client_init(void)
852 rw_init(&auimpl_client_lock, NULL, RW_DRIVER, NULL);
853 list_create(&auimpl_clients, sizeof (struct audio_client),
854 offsetof(struct audio_client, c_global_linkage));
857 void
858 auimpl_client_fini(void)
860 rw_destroy(&auimpl_client_lock);
861 list_destroy(&auimpl_clients);
864 static int
865 auimpl_stream_init(audio_stream_t *sp, audio_client_t *c)
867 mutex_init(&sp->s_lock, NULL, MUTEX_DRIVER, NULL);
868 cv_init(&sp->s_cv, NULL, CV_DRIVER, NULL);
869 sp->s_client = c;
871 if (sp == &c->c_ostream) {
872 sp->s_user_parms = &sp->s_cnv_src_parms;
873 sp->s_phys_parms = &sp->s_cnv_dst_parms;
874 sp->s_engcap = ENGINE_OUTPUT_CAP;
875 } else {
876 ASSERT(sp == &c->c_istream);
877 sp->s_user_parms = &sp->s_cnv_dst_parms;
878 sp->s_phys_parms = &sp->s_cnv_src_parms;
879 sp->s_engcap = ENGINE_INPUT_CAP;
882 /* for now initialize conversion parameters */
883 sp->s_src_quality = 3; /* reasonable compromise for now */
884 sp->s_cnv_dst_nchan = 2;
885 sp->s_cnv_dst_format = AUDIO_FORMAT_S24_NE;
886 sp->s_cnv_dst_rate = 48000;
887 sp->s_cnv_src_nchan = 2;
888 sp->s_cnv_src_format = AUDIO_FORMAT_S24_NE;
889 sp->s_cnv_src_rate = 48000;
891 /* set volume/gain all the way up */
892 sp->s_muted = B_FALSE;
893 sp->s_gain_pct = 0;
894 sp->s_gain_scaled = AUDIO_VOL_SCALE;
895 sp->s_gain_eff = AUDIO_VOL_SCALE;
898 * We have to start off with a reasonable buffer and
899 * interrupt configuration.
901 sp->s_allocsz = 65536;
902 sp->s_data = ddi_umem_alloc(sp->s_allocsz, DDI_UMEM_NOSLEEP,
903 &sp->s_cookie);
904 if (sp->s_data == NULL) {
905 sp->s_allocsz = 0;
906 audio_dev_warn(c->c_dev, "ddi_umem_alloc failed");
907 return (ENOMEM);
909 /* make sure no stale data left in stream */
910 bzero(sp->s_data, sp->s_allocsz);
913 * Allocate SRC and data conversion state.
915 mutex_enter(&sp->s_lock);
916 if (auimpl_format_alloc(sp) != 0) {
917 mutex_exit(&sp->s_lock);
918 return (ENOMEM);
921 mutex_exit(&sp->s_lock);
923 return (0);
927 static void
928 audio_stream_fini(audio_stream_t *sp)
930 auimpl_format_free(sp);
931 if (sp->s_cnv_buf0)
932 kmem_free(sp->s_cnv_buf0, sp->s_cnv_max);
933 if (sp->s_cnv_buf1)
934 kmem_free(sp->s_cnv_buf1, sp->s_cnv_max);
935 mutex_destroy(&sp->s_lock);
936 cv_destroy(&sp->s_cv);
937 if (sp->s_data != NULL) {
938 ddi_umem_free(sp->s_cookie);
939 sp->s_data = NULL;
943 void
944 auimpl_client_task(void *arg)
946 audio_client_t *c = arg;
948 mutex_enter(&c->c_lock);
950 for (;;) {
951 if (c->c_closing) {
952 break;
955 if (c->c_do_output) {
956 c->c_do_output = B_FALSE;
958 mutex_exit(&c->c_lock);
959 if (c->c_output != NULL)
960 c->c_output(c);
961 mutex_enter(&c->c_lock);
962 continue;
965 if (c->c_do_input) {
966 c->c_do_input = B_FALSE;
968 mutex_exit(&c->c_lock);
969 if (c->c_input != NULL)
970 c->c_input(c);
971 mutex_enter(&c->c_lock);
972 continue;
975 if (c->c_do_notify) {
976 c->c_do_notify = B_FALSE;
978 mutex_exit(&c->c_lock);
979 if (c->c_notify != NULL)
980 c->c_notify(c);
981 mutex_enter(&c->c_lock);
982 continue;
985 if (c->c_do_drain) {
986 c->c_do_drain = B_FALSE;
988 mutex_exit(&c->c_lock);
989 if (c->c_drain != NULL)
990 c->c_drain(c);
991 mutex_enter(&c->c_lock);
992 continue;
995 /* if we got here, we had no work to do */
996 cv_wait(&c->c_cv, &c->c_lock);
998 mutex_exit(&c->c_lock);
1002 auclnt_start_drain(audio_client_t *c)
1004 audio_stream_t *sp;
1005 int rv;
1007 sp = &c->c_ostream;
1009 /* start an asynchronous drain operation. */
1010 mutex_enter(&sp->s_lock);
1011 if (sp->s_paused || !sp->s_running) {
1012 rv = EALREADY;
1013 } else {
1014 sp->s_draining = B_TRUE;
1015 rv = 0;
1017 mutex_exit(&sp->s_lock);
1018 return (rv);
1022 auclnt_drain(audio_client_t *c)
1024 audio_stream_t *sp;
1026 sp = &c->c_ostream;
1029 * Note: Drain logic will automatically "stop" the stream when
1030 * the drain threshold has been reached. So all we have to do
1031 * is wait for the stream to stop.
1033 mutex_enter(&sp->s_lock);
1034 sp->s_draining = B_TRUE;
1035 while (sp->s_draining && sp->s_running && !sp->s_paused) {
1036 if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) {
1037 mutex_exit(&sp->s_lock);
1038 return (EINTR);
1041 mutex_exit(&sp->s_lock);
1042 return (0);
1045 audio_client_t *
1046 auimpl_client_create(dev_t dev)
1048 audio_client_ops_t *ops;
1049 audio_client_t *c;
1050 audio_client_t *next;
1051 list_t *list = &auimpl_clients;
1052 minor_t minor;
1053 audio_dev_t *d;
1054 char scratch[80];
1055 static uint64_t unique = 0;
1057 /* validate minor number */
1058 minor = getminor(dev) & AUDIO_MN_TYPE_MASK;
1059 if ((ops = audio_client_ops[minor]) == NULL) {
1060 return (NULL);
1063 /* lookup device instance */
1064 if ((d = auimpl_dev_hold_by_devt(dev)) == NULL) {
1065 audio_dev_warn(NULL, "no audio_dev for dev_t %d,%d",
1066 getmajor(dev), getminor(dev));
1067 return (NULL);
1070 if ((c = kmem_zalloc(sizeof (*c), KM_NOSLEEP)) == NULL) {
1071 audio_dev_warn(d, "unable to allocate client structure");
1072 auimpl_dev_release(d);
1073 return (NULL);
1075 c->c_dev = d;
1077 mutex_init(&c->c_lock, NULL, MUTEX_DRIVER, NULL);
1078 cv_init(&c->c_cv, NULL, CV_DRIVER, NULL);
1080 if ((auimpl_stream_init(&c->c_ostream, c) != 0) ||
1081 (auimpl_stream_init(&c->c_istream, c) != 0)) {
1082 goto failed;
1085 c->c_major = getmajor(dev);
1086 c->c_origminor = getminor(dev);
1087 c->c_ops = *ops;
1089 (void) snprintf(scratch, sizeof (scratch), "auclnt%" PRIx64,
1090 atomic_inc_64_nv(&unique));
1091 c->c_tq = ddi_taskq_create(NULL, scratch, 1, TASKQ_DEFAULTPRI, 0);
1092 if (c->c_tq == NULL) {
1093 audio_dev_warn(d, "client taskq_create failed");
1094 goto failed;
1098 * We hold the client lock here.
1100 rw_enter(&auimpl_client_lock, RW_WRITER);
1102 minor = AUDIO_MN_CLONE_MASK;
1103 for (next = list_head(list); next; next = list_next(list, next)) {
1104 if (next->c_minor > minor) {
1105 break;
1107 minor++;
1109 if (minor >= MAXMIN32) {
1110 rw_exit(&auimpl_client_lock);
1111 goto failed;
1113 c->c_minor = minor;
1114 list_insert_before(list, next, c);
1116 rw_exit(&auimpl_client_lock);
1119 return (c);
1121 failed:
1122 auimpl_dev_release(d);
1123 if (c->c_tq != NULL) {
1124 ddi_taskq_destroy(c->c_tq);
1126 audio_stream_fini(&c->c_ostream);
1127 audio_stream_fini(&c->c_istream);
1128 mutex_destroy(&c->c_lock);
1129 cv_destroy(&c->c_cv);
1130 kmem_free(c, sizeof (*c));
1131 return (NULL);
1134 void
1135 auimpl_client_destroy(audio_client_t *c)
1137 /* remove us from the global list */
1138 rw_enter(&auimpl_client_lock, RW_WRITER);
1139 list_remove(&auimpl_clients, c);
1140 rw_exit(&auimpl_client_lock);
1142 ASSERT(!c->c_istream.s_running);
1143 ASSERT(!c->c_istream.s_running);
1145 /* release the device reference count */
1146 auimpl_dev_release(c->c_dev);
1147 c->c_dev = NULL;
1149 ddi_taskq_destroy(c->c_tq);
1151 mutex_destroy(&c->c_lock);
1152 cv_destroy(&c->c_cv);
1154 audio_stream_fini(&c->c_istream);
1155 audio_stream_fini(&c->c_ostream);
1156 kmem_free(c, sizeof (*c));
1159 void
1160 auclnt_close(audio_client_t *c)
1162 audio_dev_t *d = c->c_dev;
1164 /* stop the engines if they are running */
1165 auclnt_stop(&c->c_istream);
1166 auclnt_stop(&c->c_ostream);
1168 rw_enter(&d->d_clnt_lock, RW_WRITER);
1169 list_remove(&d->d_clients, c);
1170 rw_exit(&d->d_clnt_lock);
1172 mutex_enter(&c->c_lock);
1173 /* if in transition need to wait for other thread to release */
1174 while (c->c_refcnt) {
1175 cv_wait(&c->c_cv, &c->c_lock);
1177 c->c_closing = B_TRUE;
1178 cv_broadcast(&c->c_cv);
1179 mutex_exit(&c->c_lock);
1181 /* make sure taskq has drained */
1182 ddi_taskq_wait(c->c_tq);
1184 /* release any engines that we were holding */
1185 auimpl_engine_close(&c->c_ostream);
1186 auimpl_engine_close(&c->c_istream);
1189 audio_dev_t *
1190 auclnt_hold_dev_by_index(int index)
1192 return (auimpl_dev_hold_by_index(index));
1195 void
1196 auclnt_release_dev(audio_dev_t *dev)
1198 auimpl_dev_release(dev);
1201 audio_client_t *
1202 auclnt_hold_by_devt(dev_t dev)
1204 minor_t mn = getminor(dev);
1205 major_t mj = getmajor(dev);
1206 list_t *list;
1207 audio_client_t *c;
1209 list = &auimpl_clients;
1210 /* linked list search is kind of inefficient, but it works */
1211 rw_enter(&auimpl_client_lock, RW_READER);
1212 for (c = list_head(list); c != NULL; c = list_next(list, c)) {
1213 if ((c->c_major == mj) && (c->c_minor == mn)) {
1214 mutex_enter(&c->c_lock);
1215 if (c->c_is_open) {
1216 c->c_refcnt++;
1217 mutex_exit(&c->c_lock);
1218 } else {
1219 mutex_exit(&c->c_lock);
1220 c = NULL;
1222 break;
1225 rw_exit(&auimpl_client_lock);
1226 return (c);
1229 void
1230 auclnt_release(audio_client_t *c)
1232 mutex_enter(&c->c_lock);
1233 ASSERT(c->c_refcnt > 0);
1234 c->c_refcnt--;
1235 if (c->c_refcnt == 0)
1236 cv_broadcast(&c->c_cv);
1237 mutex_exit(&c->c_lock);
1240 void
1241 auclnt_dev_walk_clients(audio_dev_t *d,
1242 int (*walker)(audio_client_t *, void *),
1243 void *arg)
1245 list_t *l = &d->d_clients;
1246 audio_client_t *c;
1247 int rv;
1249 rw_enter(&d->d_clnt_lock, RW_READER);
1250 restart:
1251 for (c = list_head(l); c != NULL; c = list_next(l, c)) {
1252 rv = (walker(c, arg));
1253 if (rv == AUDIO_WALK_STOP) {
1254 break;
1255 } else if (rv == AUDIO_WALK_RESTART) {
1256 goto restart;
1259 rw_exit(&d->d_clnt_lock);
1264 auclnt_open(audio_client_t *c, unsigned fmts, int oflag)
1266 audio_stream_t *sp;
1267 audio_dev_t *d = c->c_dev;
1268 int rv = 0;
1269 int flags;
1270 audio_parms_t parms;
1272 flags = 0;
1273 if (oflag & FNDELAY)
1274 flags |= ENGINE_NDELAY;
1276 if (oflag & FWRITE) {
1277 sp = &c->c_ostream;
1278 rv = auimpl_engine_open(d, fmts, flags | ENGINE_OUTPUT, sp);
1280 if (rv != 0) {
1281 goto done;
1283 mutex_enter(&sp->s_lock);
1284 parms = *sp->s_user_parms;
1285 rv = auimpl_format_setup(sp, &parms);
1286 mutex_exit(&sp->s_lock);
1287 if (rv != 0) {
1288 goto done;
1292 if (oflag & FREAD) {
1293 sp = &c->c_istream;
1294 rv = auimpl_engine_open(d, fmts, flags | ENGINE_INPUT, sp);
1296 if (rv != 0) {
1297 goto done;
1299 mutex_enter(&sp->s_lock);
1300 parms = *sp->s_user_parms;
1301 rv = auimpl_format_setup(sp, &parms);
1302 mutex_exit(&sp->s_lock);
1303 if (rv != 0) {
1304 goto done;
1308 if (ddi_taskq_dispatch(c->c_tq, auimpl_client_task, c, DDI_NOSLEEP) !=
1309 DDI_SUCCESS) {
1310 audio_dev_warn(d, "unable to start client taskq");
1311 rv = ENOMEM;
1314 done:
1315 if (rv != 0) {
1316 /* close any engines that we opened */
1317 auimpl_engine_close(&c->c_ostream);
1318 auimpl_engine_close(&c->c_istream);
1319 } else {
1320 rw_enter(&d->d_clnt_lock, RW_WRITER);
1321 list_insert_tail(&d->d_clients, c);
1322 c->c_ostream.s_gain_master = d->d_pcmvol;
1323 c->c_istream.s_gain_master = 100;
1324 rw_exit(&d->d_clnt_lock);
1325 auclnt_set_gain(&c->c_ostream, 100);
1326 auclnt_set_gain(&c->c_istream, 100);
1329 return (rv);
1332 minor_t
1333 auclnt_get_minor(audio_client_t *c)
1335 return (c->c_minor);
1338 minor_t
1339 auclnt_get_original_minor(audio_client_t *c)
1341 return (c->c_origminor);
1344 minor_t
1345 auclnt_get_minor_type(audio_client_t *c)
1347 return (c->c_origminor & AUDIO_MN_TYPE_MASK);
1350 queue_t *
1351 auclnt_get_rq(audio_client_t *c)
1353 return (c->c_rq);
1356 queue_t *
1357 auclnt_get_wq(audio_client_t *c)
1359 return (c->c_wq);
1362 pid_t
1363 auclnt_get_pid(audio_client_t *c)
1365 return (c->c_pid);
1368 cred_t *
1369 auclnt_get_cred(audio_client_t *c)
1371 return (c->c_cred);
1374 audio_dev_t *
1375 auclnt_get_dev(audio_client_t *c)
1377 return (c->c_dev);
1381 auclnt_get_dev_number(audio_dev_t *dev)
1383 return (dev->d_number);
1387 auclnt_get_dev_index(audio_dev_t *dev)
1389 return (dev->d_index);
1392 const char *
1393 auclnt_get_dev_name(audio_dev_t *dev)
1395 return (dev->d_name);
1398 const char *
1399 auclnt_get_dev_driver(audio_dev_t *dev)
1401 return (ddi_driver_name(dev->d_dip));
1404 dev_info_t *
1405 auclnt_get_dev_devinfo(audio_dev_t *dev)
1407 return (dev->d_dip);
1410 const char *
1411 auclnt_get_dev_hw_info(audio_dev_t *dev, void **iter)
1413 struct audio_infostr *isp = *iter;
1414 if (isp == NULL) {
1415 isp = list_head(&dev->d_hwinfo);
1416 } else {
1417 isp = list_next(&dev->d_hwinfo, isp);
1420 *iter = isp;
1421 return (isp ? isp->i_line : NULL);
1425 auclnt_get_dev_instance(audio_dev_t *dev)
1427 return (dev->d_instance);
1430 const char *
1431 auclnt_get_dev_description(audio_dev_t *dev)
1433 return (dev->d_desc);
1436 const char *
1437 auclnt_get_dev_version(audio_dev_t *dev)
1439 return (dev->d_vers);
1442 unsigned
1443 auclnt_get_dev_capab(audio_dev_t *dev)
1445 uint32_t flags;
1446 unsigned caps = 0;
1448 flags = dev->d_flags;
1450 if (flags & DEV_OUTPUT_CAP)
1451 caps |= AUDIO_CLIENT_CAP_PLAY;
1452 if (flags & DEV_INPUT_CAP)
1453 caps |= AUDIO_CLIENT_CAP_RECORD;
1454 if (flags & DEV_DUPLEX_CAP)
1455 caps |= AUDIO_CLIENT_CAP_DUPLEX;
1457 /* AC3: deal with formats that don't support mixing */
1459 return (caps);
1462 void
1463 auclnt_notify_dev(audio_dev_t *dev)
1465 list_t *l = &dev->d_clients;
1466 audio_client_t *c;
1468 rw_enter(&dev->d_clnt_lock, RW_READER);
1469 for (c = list_head(l); c != NULL; c = list_next(l, c)) {
1470 mutex_enter(&c->c_lock);
1471 c->c_do_notify = B_TRUE;
1472 cv_broadcast(&c->c_cv);
1473 mutex_exit(&c->c_lock);
1475 rw_exit(&dev->d_clnt_lock);
1478 uint64_t
1479 auclnt_get_samples(audio_stream_t *sp)
1481 uint64_t n;
1483 mutex_enter(&sp->s_lock);
1484 n = sp->s_samples;
1485 mutex_exit(&sp->s_lock);
1486 return (n);
1489 void
1490 auclnt_set_samples(audio_stream_t *sp, uint64_t n)
1492 mutex_enter(&sp->s_lock);
1493 sp->s_samples = n;
1494 mutex_exit(&sp->s_lock);
1497 uint64_t
1498 auclnt_get_errors(audio_stream_t *sp)
1500 uint64_t n;
1501 mutex_enter(&sp->s_lock);
1502 n = sp->s_errors;
1503 mutex_exit(&sp->s_lock);
1504 return (n);
1507 void
1508 auclnt_set_errors(audio_stream_t *sp, uint64_t n)
1510 mutex_enter(&sp->s_lock);
1511 sp->s_errors = n;
1512 mutex_exit(&sp->s_lock);
1515 void
1516 auclnt_register_ops(minor_t minor, audio_client_ops_t *ops)
1518 /* we control minor number allocations, no need for runtime checks */
1519 ASSERT(minor <= AUDIO_MN_TYPE_MASK);
1521 audio_client_ops[minor] = ops;
1525 auimpl_create_minors(audio_dev_t *d)
1527 char path[MAXPATHLEN];
1528 int rv = 0;
1529 minor_t minor;
1530 audio_client_ops_t *ops;
1531 char *nt;
1533 for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) {
1535 if ((ops = audio_client_ops[i]) == NULL)
1536 continue;
1538 if (ops->aco_dev_init != NULL)
1539 d->d_minor_data[i] = ops->aco_dev_init(d);
1541 switch (i) {
1542 case AUDIO_MINOR_SNDSTAT:
1543 if (!(d->d_flags & DEV_SNDSTAT_CAP)) {
1544 continue;
1546 nt = DDI_PSEUDO;
1547 break;
1549 default:
1550 if (!(d->d_flags & (DEV_INPUT_CAP| DEV_OUTPUT_CAP))) {
1551 continue;
1553 nt = DDI_NT_AUDIO;
1554 break;
1557 if (ops->aco_minor_prefix != NULL) {
1559 minor = AUDIO_MKMN(d->d_instance, i);
1560 (void) snprintf(path, sizeof (path),
1561 "%s%d", ops->aco_minor_prefix, d->d_instance);
1563 rv = ddi_create_minor_node(d->d_dip, path, S_IFCHR,
1564 minor, nt, 0);
1566 if (rv != 0)
1567 break;
1570 return (rv);
1573 void
1574 auimpl_remove_minors(audio_dev_t *d)
1576 char path[MAXPATHLEN];
1577 audio_client_ops_t *ops;
1579 for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) {
1580 if ((ops = audio_client_ops[i]) == NULL)
1581 continue;
1582 if (ops->aco_minor_prefix != NULL) {
1583 (void) snprintf(path, sizeof (path), "%s%d",
1584 ops->aco_minor_prefix, d->d_instance);
1585 (void) ddi_remove_minor_node(d->d_dip, path);
1588 if (ops->aco_dev_fini != NULL)
1589 ops->aco_dev_fini(d->d_minor_data[i]);
1593 void *
1594 auclnt_get_dev_minor_data(audio_dev_t *d, minor_t mn)
1596 ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS));
1597 return (d->d_minor_data[mn]);
1600 void *
1601 auclnt_get_minor_data(audio_client_t *c, minor_t mn)
1603 ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS));
1604 return (c->c_dev->d_minor_data[mn]);
1608 * This will walk all controls registered to a clients device and callback
1609 * to walker for each one with its audio_ctrl. Note this data
1610 * must be considered read only by walker.
1612 * Note that walk_func may return values to continue (AUDIO_WALK_CONTINUE)
1613 * or stop walk (AUDIO_WALK_STOP).
1616 void
1617 auclnt_walk_controls(audio_dev_t *d,
1618 int (*walker)(audio_ctrl_t *, void *),
1619 void *arg)
1621 audio_ctrl_t *ctrl;
1623 rw_enter(&d->d_ctrl_lock, RW_READER);
1624 for (ctrl = list_head(&d->d_controls); ctrl;
1625 ctrl = list_next(&d->d_controls, ctrl)) {
1626 if (walker(ctrl, arg) == AUDIO_WALK_STOP)
1627 break;
1629 rw_exit(&d->d_ctrl_lock);
1633 * This will search all controls attached to an
1634 * audio device for a control with the desired name.
1636 * d - the audio device to look on
1637 * name - name of the control being looked for.
1639 * On successful return a ctrl handle will be returned. On
1640 * failure NULL is returned.
1642 audio_ctrl_t *
1643 auclnt_find_control(audio_dev_t *d, const char *name)
1645 audio_ctrl_t *ctrl;
1647 /* Verify argument */
1648 ASSERT(d);
1650 rw_enter(&d->d_ctrl_lock, RW_READER);
1651 for (ctrl = list_head(&d->d_controls); ctrl;
1652 ctrl = list_next(&d->d_controls, ctrl)) {
1653 if (strcmp(ctrl->ctrl_name, name) == 0) {
1654 rw_exit(&d->d_ctrl_lock);
1655 return (ctrl);
1658 rw_exit(&d->d_ctrl_lock);
1659 return (NULL);
1663 * Given a known control, get its attributes.
1665 * The caller must supply a audio_ctrl_desc_t structure. Also the
1666 * values in the structure are ignored when making the call and filled
1667 * in by this function. All data pointed to by elements of desc should
1668 * be assumed read only.
1670 * If an error occurs then a non-zero is returned.
1674 auclnt_control_describe(audio_ctrl_t *ctrl, audio_ctrl_desc_t *desc)
1676 ASSERT(ctrl);
1677 ASSERT(desc);
1679 bcopy(&ctrl->ctrl_des, desc, sizeof (*desc));
1680 return (0);
1684 auclnt_control_read(audio_ctrl_t *ctrl, uint64_t *value)
1686 return (audio_control_read(ctrl, value));
1690 auclnt_control_write(audio_ctrl_t *ctrl, uint64_t value)
1692 return (audio_control_write(ctrl, value));
1695 void
1696 auclnt_warn(audio_client_t *c, const char *fmt, ...)
1698 va_list va;
1700 va_start(va, fmt);
1701 auimpl_dev_vwarn(c ? c->c_dev : NULL, fmt, va);
1702 va_end(va);