1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (C) 4Front Technologies 1996-2008.
23 *
24 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 #include <sys/types.h>
29 #include <sys/list.h>
30 #include <sys/sysmacros.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/callb.h>
34 #include <sys/kstat.h>
35 #include <sys/note.h>
36
37 #include "audio_impl.h"
38
39 /*
40 * Audio Engine functions.
41 */
42
43 /*
44 * Globals
45 */
46 uint_t audio_intrhz = AUDIO_INTRHZ;
47 /*
48 * We need to operate at fairly high interrupt priority to avoid
49 * underruns due to other less time sensitive processing.
50 */
51 int audio_priority = DDI_IPL_8;
52
53 audio_dev_t *
audio_dev_alloc(dev_info_t * dip,int instance)54 audio_dev_alloc(dev_info_t *dip, int instance)
55 {
56 audio_dev_t *d;
57
58 /*
59 * For a card with multiple independent audio ports on it, we
60 * allow the driver to provide a different instance numbering
61 * scheme than the standard DDI instance number. (This is
62 * sort of like the PPA numbering scheme used by NIC drivers
63 * -- by default PPA == instance, but sometimes we need more
64 * flexibility.)
65 */
66 if (instance == 0) {
67 instance = ddi_get_instance(dip);
68 }
69 /* generally this shouldn't occur */
70 if (instance > AUDIO_MN_INST_MASK) {
71 audio_dev_warn(NULL, "bad instance number for %s (%d)",
72 ddi_driver_name(dip), instance);
73 return (NULL);
74 }
75
76 if ((d = kmem_zalloc(sizeof (*d), KM_NOSLEEP)) == NULL) {
77 audio_dev_warn(NULL, "unable to allocate audio device struct");
78 return (NULL);
79 }
80 d->d_dip = dip;
81 d->d_number = -1;
82 d->d_major = ddi_driver_major(dip);
83 d->d_instance = instance;
84 d->d_pcmvol = 100;
85 mutex_init(&d->d_lock, NULL, MUTEX_DRIVER, NULL);
86 cv_init(&d->d_cv, NULL, CV_DRIVER, NULL);
87 mutex_init(&d->d_ctrl_lock, NULL, MUTEX_DRIVER, NULL);
88 cv_init(&d->d_ctrl_cv, NULL, CV_DRIVER, NULL);
89 list_create(&d->d_clients, sizeof (struct audio_client),
90 offsetof(struct audio_client, c_dev_linkage));
91 list_create(&d->d_engines, sizeof (struct audio_engine),
92 offsetof(struct audio_engine, e_dev_linkage));
93 list_create(&d->d_controls, sizeof (struct audio_ctrl),
94 offsetof(struct audio_ctrl, ctrl_linkage));
95 list_create(&d->d_hwinfo, sizeof (struct audio_infostr),
96 offsetof(struct audio_infostr, i_linkage));
97 (void) snprintf(d->d_name, sizeof (d->d_name), "%s#%d",
98 ddi_driver_name(dip), instance);
99
100 return (d);
101 }
102
103 void
audio_dev_free(audio_dev_t * d)104 audio_dev_free(audio_dev_t *d)
105 {
106 struct audio_infostr *isp;
107
108 while ((isp = list_remove_head(&d->d_hwinfo)) != NULL) {
109 kmem_free(isp, sizeof (*isp));
110 }
111 if (d->d_pcmvol_ctrl != NULL) {
112 audio_dev_del_control(d->d_pcmvol_ctrl);
113 }
114 list_destroy(&d->d_hwinfo);
115 list_destroy(&d->d_engines);
116 list_destroy(&d->d_controls);
117 list_destroy(&d->d_clients);
118 mutex_destroy(&d->d_ctrl_lock);
119 mutex_destroy(&d->d_lock);
120 cv_destroy(&d->d_cv);
121 cv_destroy(&d->d_ctrl_cv);
122 kmem_free(d, sizeof (*d));
123 }
124
125 void
audio_dev_set_description(audio_dev_t * d,const char * desc)126 audio_dev_set_description(audio_dev_t *d, const char *desc)
127 {
128 (void) strlcpy(d->d_desc, desc, sizeof (d->d_desc));
129 }
130
131 void
audio_dev_set_version(audio_dev_t * d,const char * vers)132 audio_dev_set_version(audio_dev_t *d, const char *vers)
133 {
134 (void) strlcpy(d->d_vers, vers, sizeof (d->d_vers));
135 }
136
137 void
audio_dev_add_info(audio_dev_t * d,const char * info)138 audio_dev_add_info(audio_dev_t *d, const char *info)
139 {
140 struct audio_infostr *isp;
141
142 /* failure to add information structure is not critical */
143 isp = kmem_zalloc(sizeof (*isp), KM_NOSLEEP);
144 if (isp == NULL) {
145 audio_dev_warn(d, "unable to allocate information structure");
146 } else {
147 (void) snprintf(isp->i_line, sizeof (isp->i_line), info);
148 list_insert_tail(&d->d_hwinfo, isp);
149 }
150 }
151
152 static void
auimpl_engine_reset(audio_engine_t * e)153 auimpl_engine_reset(audio_engine_t *e)
154 {
155 char *buf;
156 char *ptr;
157 int nfr, resid, cnt;
158 int tidx;
159
160 tidx = e->e_tidx;
161 nfr = min(e->e_head - e->e_tail, e->e_nframes);
162 buf = kmem_alloc(nfr * e->e_framesz, KM_SLEEP);
163 ptr = buf;
164 cnt = 0;
165
166 ASSERT(e->e_nframes);
167
168 for (resid = nfr; resid; resid -= cnt) {
169 int nbytes;
170
171 cnt = min((e->e_nframes - tidx), resid);
172 nbytes = cnt * e->e_framesz;
173
174 bcopy(e->e_data + (tidx * e->e_framesz), ptr, nbytes);
175 ptr += nbytes;
176 tidx += cnt;
177 if (tidx == e->e_nframes) {
178 tidx = 0;
179 }
180 }
181
182 if (e->e_flags & ENGINE_INPUT) {
183 /* record */
184 e->e_hidx = 0;
185 e->e_tidx = (e->e_nframes - nfr) % e->e_nframes;
186 } else {
187 /* play */
188 e->e_hidx = nfr % e->e_nframes;
189 e->e_tidx = 0;
190 }
191
192 /* relocate from scratch area to destination */
193 bcopy(buf, e->e_data + (e->e_tidx * e->e_framesz), nfr * e->e_framesz);
194 kmem_free(buf, nfr * e->e_framesz);
195 }
196
197 static volatile uint_t auimpl_engno = 0;
198
199 audio_engine_t *
audio_engine_alloc(audio_engine_ops_t * ops,uint_t flags)200 audio_engine_alloc(audio_engine_ops_t *ops, uint_t flags)
201 {
202 int i;
203 audio_engine_t *e;
204 char tname[32];
205 int num;
206
207 if (ops->audio_engine_version != AUDIO_ENGINE_VERSION) {
208 audio_dev_warn(NULL, "audio engine version mismatch: %d != %d",
209 ops->audio_engine_version, AUDIO_ENGINE_VERSION);
210 return (NULL);
211 }
212
213 /* NB: The ops vector must be held in persistent storage! */
214 e = kmem_zalloc(sizeof (audio_engine_t), KM_NOSLEEP);
215 if (e == NULL) {
216 audio_dev_warn(NULL, "unable to allocate engine struct");
217 return (NULL);
218 }
219 e->e_ops = *ops;
220 mutex_init(&e->e_lock, NULL, MUTEX_DRIVER,
221 DDI_INTR_PRI(audio_priority));
222 cv_init(&e->e_cv, NULL, CV_DRIVER, NULL);
223 list_create(&e->e_streams, sizeof (struct audio_stream),
224 offsetof(struct audio_stream, s_eng_linkage));
225
226 for (i = 0; i < AUDIO_MAX_CHANNELS; i++) {
227 e->e_chbufs[i] = kmem_zalloc(sizeof (int32_t) * AUDIO_CHBUFS,
228 KM_NOSLEEP);
229 if (e->e_chbufs[i] == NULL) {
230 audio_dev_warn(NULL, "unable to allocate channel buf");
231 audio_engine_free(e);
232 return (NULL);
233 }
234 }
235
236 num = atomic_inc_uint_nv(&auimpl_engno);
237
238 (void) snprintf(tname, sizeof (tname), "audio_engine_%d", num);
239
240 e->e_flags = flags & ENGINE_DRIVER_FLAGS;
241 return (e);
242 }
243
244 void
audio_engine_free(audio_engine_t * e)245 audio_engine_free(audio_engine_t *e)
246 {
247 int i;
248
249 for (i = 0; i < AUDIO_MAX_CHANNELS; i++) {
250 if (e->e_chbufs[i] != NULL) {
251 kmem_free(e->e_chbufs[i],
252 sizeof (int32_t) * AUDIO_CHBUFS);
253 }
254 }
255
256 list_destroy(&e->e_streams);
257 mutex_destroy(&e->e_lock);
258 cv_destroy(&e->e_cv);
259 kmem_free(e, sizeof (*e));
260 }
261
262 static list_t auimpl_devs_by_index;
263 static list_t auimpl_devs_by_number;
264 static krwlock_t auimpl_dev_lock;
265
266 /*
267 * Not for public consumption: Private interfaces.
268 */
269 void
auimpl_dev_hold(audio_dev_t * d)270 auimpl_dev_hold(audio_dev_t *d)
271 {
272 /* bump the reference count */
273 mutex_enter(&d->d_lock);
274 d->d_refcnt++;
275 mutex_exit(&d->d_lock);
276 }
277
278 audio_dev_t *
auimpl_dev_hold_by_devt(dev_t dev)279 auimpl_dev_hold_by_devt(dev_t dev)
280 {
281 audio_dev_t *d;
282 major_t major;
283 int instance;
284 list_t *l = &auimpl_devs_by_index;
285
286 major = getmajor(dev);
287 instance = (getminor(dev) >> AUDIO_MN_INST_SHIFT) & AUDIO_MN_INST_MASK;
288
289 rw_enter(&auimpl_dev_lock, RW_READER);
290
291 for (d = list_head(l); d; d = list_next(l, d)) {
292 if ((d->d_major == major) && (d->d_instance == instance)) {
293 auimpl_dev_hold(d);
294 break;
295 }
296 }
297
298 rw_exit(&auimpl_dev_lock);
299 return (d);
300 }
301
302 audio_dev_t *
auimpl_dev_hold_by_index(int index)303 auimpl_dev_hold_by_index(int index)
304 {
305 audio_dev_t *d;
306 list_t *l = &auimpl_devs_by_index;
307
308 rw_enter(&auimpl_dev_lock, RW_READER);
309
310 for (d = list_head(l); d; d = list_next(l, d)) {
311 if (d->d_index == index) {
312 auimpl_dev_hold(d);
313 break;
314 }
315 }
316
317 rw_exit(&auimpl_dev_lock);
318 return (d);
319 }
320
321 void
auimpl_dev_release(audio_dev_t * d)322 auimpl_dev_release(audio_dev_t *d)
323 {
324 mutex_enter(&d->d_lock);
325 d->d_refcnt--;
326 mutex_exit(&d->d_lock);
327 }
328
329 int
auimpl_choose_format(int fmts)330 auimpl_choose_format(int fmts)
331 {
332 /*
333 * Choose the very best format we can. We choose 24 bit in
334 * preference to 32 bit because we mix in 24 bit. We do that
335 * to allow overflows to fit within 32-bits. (Very few humans
336 * can tell a difference between 24 and 32 bit audio anyway.)
337 */
338 if (fmts & AUDIO_FORMAT_S24_NE)
339 return (AUDIO_FORMAT_S24_NE);
340
341 if (fmts & AUDIO_FORMAT_S32_NE)
342 return (AUDIO_FORMAT_S32_NE);
343
344 if (fmts & AUDIO_FORMAT_S24_OE)
345 return (AUDIO_FORMAT_S24_OE);
346
347 if (fmts & AUDIO_FORMAT_S32_OE)
348 return (AUDIO_FORMAT_S32_OE);
349
350 if (fmts & AUDIO_FORMAT_S16_NE)
351 return (AUDIO_FORMAT_S16_NE);
352
353 if (fmts & AUDIO_FORMAT_S16_OE)
354 return (AUDIO_FORMAT_S16_OE);
355
356 if (fmts & AUDIO_FORMAT_AC3)
357 return (AUDIO_FORMAT_AC3);
358
359 return (AUDIO_FORMAT_NONE);
360 }
361
362 int
auimpl_engine_open(audio_stream_t * sp,int flags)363 auimpl_engine_open(audio_stream_t *sp, int flags)
364 {
365 return (auimpl_engine_setup(sp, flags, NULL, FORMAT_MSK_NONE));
366 }
367
368
369 int
auimpl_engine_setup(audio_stream_t * sp,int flags,audio_parms_t * parms,uint_t mask)370 auimpl_engine_setup(audio_stream_t *sp, int flags, audio_parms_t *parms,
371 uint_t mask)
372 {
373 audio_dev_t *d = sp->s_client->c_dev;
374 audio_engine_t *e = NULL;
375 audio_parms_t uparms;
376 list_t *list;
377 uint_t cap;
378 int priority = 0;
379 int rv = ENODEV;
380 int sampsz;
381 int i;
382 int fragfr;
383 int fmts;
384
385
386 mutex_enter(&d->d_lock);
387
388 uparms = *sp->s_user_parms;
389 if (mask & FORMAT_MSK_FMT)
390 uparms.p_format = parms->p_format;
391 if (mask & FORMAT_MSK_RATE)
392 uparms.p_rate = parms->p_rate;
393 if (mask & FORMAT_MSK_CHAN)
394 uparms.p_nchan = parms->p_nchan;
395
396 /*
397 * Which direction are we opening? (We must open exactly
398 * one direction, otherwise the open is meaningless.)
399 */
400
401 if (sp == &sp->s_client->c_ostream) {
402 cap = ENGINE_OUTPUT_CAP;
403 flags |= ENGINE_OUTPUT;
404 } else {
405 cap = ENGINE_INPUT_CAP;
406 flags |= ENGINE_INPUT;
407 }
408
409 if (uparms.p_format == AUDIO_FORMAT_AC3) {
410 fmts = AUDIO_FORMAT_AC3;
411 flags |= ENGINE_EXCLUSIVE;
412 } else {
413 fmts = AUDIO_FORMAT_PCM;
414 }
415
416 list = &d->d_engines;
417
418
419 /* If the device is suspended, wait for it to resume. */
420 while (d->d_suspended) {
421 cv_wait(&d->d_ctrl_cv, &d->d_lock);
422 }
423
424 again:
425
426 for (audio_engine_t *t = list_head(list); t; t = list_next(list, t)) {
427 int mypri;
428 int r;
429
430 /* Make sure the engine can do what we want it to. */
431 mutex_enter(&t->e_lock);
432
433 if ((t->e_flags & cap) == 0) {
434 mutex_exit(&t->e_lock);
435 continue;
436 }
437
438 /*
439 * Open the engine early, as the inquiries to rate and format
440 * may not be accurate until this is done.
441 */
442 if (list_is_empty(&t->e_streams)) {
443 if (ENG_OPEN(t, flags, &t->e_nframes, &t->e_data)) {
444 mutex_exit(&t->e_lock);
445 rv = EIO;
446 continue;
447 }
448 }
449
450 if ((ENG_FORMAT(t) & fmts) == 0) {
451 if (list_is_empty(&t->e_streams))
452 ENG_CLOSE(t);
453 mutex_exit(&t->e_lock);
454 continue;
455 }
456
457
458 /* If it is in failed state, don't use this engine. */
459 if (t->e_failed) {
460 if (list_is_empty(&t->e_streams))
461 ENG_CLOSE(t);
462 mutex_exit(&t->e_lock);
463 rv = rv ? EIO : 0;
464 continue;
465 }
466
467 /*
468 * If the engine is in exclusive use, we can't use it.
469 * This is intended for use with AC3 or digital
470 * streams that cannot tolerate mixing.
471 */
472 if ((t->e_flags & ENGINE_EXCLUSIVE) && (t != sp->s_engine)) {
473 if (list_is_empty(&t->e_streams))
474 ENG_CLOSE(t);
475 mutex_exit(&t->e_lock);
476 rv = rv ? EBUSY : 0;
477 continue;
478 }
479
480 /*
481 * If the engine is in use incompatibly, we can't use
482 * it. This should only happen for half-duplex audio
483 * devices. I've not seen any of these that are
484 * recent enough to be supported by Solaris.
485 */
486 if (((flags & ENGINE_INPUT) && (t->e_flags & ENGINE_OUTPUT)) ||
487 ((flags & ENGINE_OUTPUT) && (t->e_flags & ENGINE_INPUT))) {
488 if (list_is_empty(&t->e_streams))
489 ENG_CLOSE(t);
490 mutex_exit(&t->e_lock);
491 /* Only override the ENODEV or EIO. */
492 rv = rv ? EBUSY : 0;
493 continue;
494 }
495
496 /*
497 * In order to support as many different possible
498 * output streams (e.g. AC3 passthru or AC3 decode),
499 * or multiple exclusive outputs, we treat audio
500 * engines as *precious*.
501 *
502 * This means that we will try hard to reuse an
503 * existing allocated engine. This may not be the
504 * optimal performance configuration (especially if we
505 * wanted to avoid rate conversion, for example), but
506 * it should have fewer cases where the configuration
507 * results in denying service to any client.
508 */
509
510 /*
511 * This engine *can* support us, so we should no longer
512 * have a failure mode.
513 */
514 rv = 0;
515 mypri = (1U << 0);
516
517
518 /*
519 * Mixing is cheap, so try not to pick on idle
520 * engines. This avoids burning bus bandwidth (which
521 * may be precious for certain classes of traffic).
522 * Note that idleness is given a low priority compared
523 * to the other considerations.
524 *
525 * We also use this opportunity open the engine, if
526 * not already done so, so that our parameter
527 * inquiries will be valid.
528 */
529 if (!list_is_empty(&t->e_streams))
530 mypri |= (1U << 1);
531
532 /*
533 * Slight preference is given to reuse an engine that
534 * we might already be using.
535 */
536 if (t == sp->s_engine)
537 mypri |= (1U << 2);
538
539
540 /*
541 * Sample rate conversion avoidance. Upsampling
542 * requires multiplications and is moderately
543 * expensive. Downsampling requires division and is
544 * quite expensive, and hence to be avoided if at all
545 * possible.
546 */
547 r = ENG_RATE(t);
548 if (uparms.p_rate == r) {
549 /*
550 * No conversion needed at all. This is ideal.
551 */
552 mypri |= (1U << 4) | (1U << 3);
553 } else {
554 int src, dst;
555
556 if (flags & ENGINE_INPUT) {
557 src = r;
558 dst = uparms.p_rate;
559 } else {
560 src = uparms.p_rate;
561 dst = r;
562 }
563 if ((src < dst) && ((dst % src) == 0)) {
564 /*
565 * Pure upsampling only. This
566 * penalizes any engine which requires
567 * downsampling.
568 */
569 mypri |= (1U << 3);
570 }
571 }
572
573 /*
574 * Try not to pick on duplex engines. This way we
575 * leave engines that can be used for recording or
576 * playback available as such. All modern drivers
577 * use separate unidirectional engines for playback
578 * and record.
579 */
580 if ((t->e_flags & ENGINE_CAPS) == cap) {
581 mypri |= (1U << 5);
582 }
583
584 /*
585 * Try not to pick on engines that can do other
586 * formats. This will generally be false, but if it
587 * happens we pretty strongly avoid using a limited
588 * resource.
589 */
590 if ((t->e_format & ~fmts) == 0) {
591 mypri |= (1U << 6);
592 }
593
594 if (mypri > priority) {
595 if (e != NULL) {
596 /*
597 * If we opened this for our own use
598 * and we are no longer using it, then
599 * close it back down.
600 */
601 if (list_is_empty(&e->e_streams))
602 ENG_CLOSE(e);
603 mutex_exit(&e->e_lock);
604 }
605 e = t;
606 priority = mypri;
607 } else {
608 mutex_exit(&t->e_lock);
609 }
610
611 /*
612 * Locking: at this point, if we have an engine, "e", it is
613 * locked. No other engines should have a lock held.
614 */
615 }
616
617 if ((rv == EBUSY) && ((flags & ENGINE_NDELAY) == 0)) {
618 ASSERT(e == NULL);
619 if (cv_wait_sig(&d->d_cv, &d->d_lock) == 0) {
620 mutex_exit(&d->d_lock);
621 return (EINTR);
622 }
623 goto again;
624 }
625
626 if (rv != 0) {
627 ASSERT(e == NULL);
628 mutex_exit(&d->d_lock);
629 return (rv);
630 }
631
632 ASSERT(e != NULL);
633 ASSERT(mutex_owned(&e->e_lock));
634
635 if (sp->s_engine && (sp->s_engine != e)) {
636 /*
637 * If this represents a potential engine change, then
638 * we close off everything, and start anew. This turns
639 * out to be vastly simpler than trying to close all
640 * the races associated with a true hand off. This
641 * ought to be relatively uncommon (changing engines).
642 */
643
644 /* Drop the new reference. */
645 if (list_is_empty(&e->e_streams))
646 ENG_CLOSE(e);
647 mutex_exit(&e->e_lock);
648 mutex_exit(&d->d_lock);
649
650 auimpl_engine_close(sp);
651
652 /* Try again. */
653 return (auimpl_engine_setup(sp, flags, parms, mask));
654 }
655
656 if (sp->s_engine == NULL) {
657 /*
658 * Add a reference to this engine if we don't already
659 * have one.
660 */
661 sp->s_engine = e;
662
663 if (!list_is_empty(&e->e_streams)) {
664 /*
665 * If the engine is already open, there is no
666 * need for further work. The first open will
667 * be relatively expensive, but subsequent
668 * opens should be as cheap as possible.
669 */
670 list_insert_tail(&e->e_streams, sp);
671 goto ok;
672 }
673 list_insert_tail(&e->e_streams, sp);
674
675 } else {
676 ASSERT(sp->s_engine == e);
677 /*
678 * No change in engine... hence don't reprogram the
679 * engine, and don't change references.
680 */
681 goto ok;
682 }
683
684 e->e_format = ENG_FORMAT(e);
685 e->e_nchan = ENG_CHANNELS(e);
686 e->e_rate = ENG_RATE(e);
687
688 /* Select format converters for the engine. */
689 switch (e->e_format) {
690 case AUDIO_FORMAT_S24_NE:
691 e->e_export = auimpl_export_24ne;
692 e->e_import = auimpl_import_24ne;
693 sampsz = 4;
694 break;
695 case AUDIO_FORMAT_S32_NE:
696 e->e_export = auimpl_export_32ne;
697 e->e_import = auimpl_import_32ne;
698 sampsz = 4;
699 break;
700 case AUDIO_FORMAT_S24_OE:
701 e->e_export = auimpl_export_24oe;
702 e->e_import = auimpl_import_24oe;
703 sampsz = 4;
704 break;
705 case AUDIO_FORMAT_S32_OE:
706 e->e_export = auimpl_export_32oe;
707 e->e_import = auimpl_import_32oe;
708 sampsz = 4;
709 break;
710 case AUDIO_FORMAT_S16_NE:
711 e->e_export = auimpl_export_16ne;
712 e->e_import = auimpl_import_16ne;
713 sampsz = 2;
714 break;
715 case AUDIO_FORMAT_S16_OE:
716 e->e_export = auimpl_export_16oe;
717 e->e_import = auimpl_import_16oe;
718 sampsz = 2;
719 break;
720 case AUDIO_FORMAT_AC3:
721 e->e_export = auimpl_export_24ne;
722 e->e_import = auimpl_import_24ne;
723 flags |= ENGINE_EXCLUSIVE;
724 sampsz = 2;
725 break;
726 default:
727 audio_dev_warn(d, "bad format");
728 rv = ENOTSUP;
729 goto done;
730 }
731
732 fragfr = e->e_rate / audio_intrhz;
733 if ((fragfr > AUDIO_CHBUFS) || (fragfr < 1)) {
734 audio_dev_warn(d, "invalid fragment configration");
735 rv = EINVAL;
736 goto done;
737 }
738
739 /* Sanity test a few values. */
740 if ((e->e_nchan < 0) || (e->e_nchan > AUDIO_MAX_CHANNELS) ||
741 (e->e_rate < 5000) || (e->e_rate > 192000)) {
742 audio_dev_warn(d, "bad engine channels or rate");
743 rv = EINVAL;
744 goto done;
745 }
746
747 if ((e->e_nframes <= (fragfr * 2)) || (e->e_data == NULL)) {
748 audio_dev_warn(d, "improper engine configuration");
749 rv = EINVAL;
750 goto done;
751 }
752
753 e->e_framesz = e->e_nchan * sampsz;
754 e->e_fragfr = fragfr;
755 e->e_head = 0;
756 e->e_tail = 0;
757 e->e_hidx = 0;
758 e->e_tidx = 0;
759 e->e_limiter_state = 0x10000;
760 bzero(e->e_data, e->e_nframes * e->e_framesz);
761
762 if (e->e_ops.audio_engine_playahead == NULL) {
763 e->e_playahead = (fragfr * 3) / 2;
764 } else {
765 e->e_playahead = ENG_PLAYAHEAD(e);
766 /*
767 * Need to have at least a fragment plus some extra to
768 * avoid underruns.
769 */
770 if (e->e_playahead < ((fragfr * 3) / 2)) {
771 e->e_playahead = (fragfr * 3) / 2;
772 }
773
774 /*
775 * Impossible to queue more frames than FIFO can hold.
776 */
777 if (e->e_playahead > e->e_nframes) {
778 e->e_playahead = (fragfr * 3) / 2;
779 }
780 }
781
782 for (i = 0; i < e->e_nchan; i++) {
783 if (e->e_ops.audio_engine_chinfo == NULL) {
784 e->e_choffs[i] = i;
785 e->e_chincr[i] = e->e_nchan;
786 } else {
787 ENG_CHINFO(e, i, &e->e_choffs[i], &e->e_chincr[i]);
788 }
789 }
790
791 e->e_flags |= flags;
792
793 /*
794 * Arrange for the engine to be started. We defer this to the
795 * periodic callback, to ensure that the start happens near
796 * the edge of the periodic callback. This is necessary to
797 * ensure that the first fragment processed is about the same
798 * size as the usual fragment size. (Basically, the problem
799 * is that we have only 10 msec resolution with the periodic
800 * interface, whch is rather unfortunate.)
801 */
802 e->e_need_start = B_TRUE;
803
804 if (flags & ENGINE_OUTPUT) {
805 /*
806 * Start the output callback to populate the engine on
807 * startup. This avoids a false underrun when we're
808 * first starting up.
809 */
810 auimpl_output_preload(e);
811
812 e->e_periodic = ddi_periodic_add(auimpl_output_callback, e,
813 NANOSEC / audio_intrhz, audio_priority);
814 } else {
815 e->e_periodic = ddi_periodic_add(auimpl_input_callback, e,
816 NANOSEC / audio_intrhz, audio_priority);
817 }
818
819 ok:
820 sp->s_phys_parms->p_rate = e->e_rate;
821 sp->s_phys_parms->p_nchan = e->e_nchan;
822
823 /* Configure the engine. */
824 mutex_enter(&sp->s_lock);
825 rv = auimpl_format_setup(sp, parms, mask);
826 mutex_exit(&sp->s_lock);
827
828 done:
829 mutex_exit(&e->e_lock);
830 mutex_exit(&d->d_lock);
831
832 return (rv);
833 }
834
835 void
auimpl_engine_close(audio_stream_t * sp)836 auimpl_engine_close(audio_stream_t *sp)
837 {
838 audio_engine_t *e = sp->s_engine;
839 audio_dev_t *d;
840 ddi_periodic_t ep;
841
842 if (e == NULL)
843 return;
844
845 d = e->e_dev;
846 ep = 0;
847
848 mutex_enter(&d->d_lock);
849 while (d->d_suspended) {
850 cv_wait(&d->d_ctrl_cv, &d->d_lock);
851 }
852
853 mutex_enter(&e->e_lock);
854 sp->s_engine = NULL;
855 list_remove(&e->e_streams, sp);
856 if (list_is_empty(&e->e_streams)) {
857 ENG_STOP(e);
858 ep = e->e_periodic;
859 e->e_periodic = 0;
860 e->e_flags &= ENGINE_DRIVER_FLAGS;
861 ENG_CLOSE(e);
862 }
863 mutex_exit(&e->e_lock);
864
865 if (ep != 0)
866 ddi_periodic_delete(ep);
867
868 cv_broadcast(&d->d_cv);
869 mutex_exit(&d->d_lock);
870 }
871
872 int
audio_dev_register(audio_dev_t * d)873 audio_dev_register(audio_dev_t *d)
874 {
875 list_t *l;
876 audio_dev_t *srch;
877 int start;
878
879 /*
880 * Make sure we don't automatically unload. This prevents
881 * loss of hardware settings when no audio clients are
882 * running.
883 */
884 (void) ddi_prop_update_int(DDI_DEV_T_NONE, d->d_dip,
885 DDI_NO_AUTODETACH, 1);
886
887 /*
888 * This does an in-order insertion, finding the first available
889 * free index. "Special" devices (ones without any actual engines)
890 * are all numbered 0. There should only be one of them anyway.
891 * All others start at one.
892 */
893 if (d->d_flags & DEV_SNDSTAT_CAP) {
894 start = 0;
895 } else {
896 start = 1;
897 }
898 d->d_index = start;
899
900 rw_enter(&auimpl_dev_lock, RW_WRITER);
901 l = &auimpl_devs_by_index;
902 for (srch = list_head(l); srch; srch = list_next(l, srch)) {
903 /* skip over special nodes */
904 if (srch->d_index < start)
905 continue;
906 if (srch->d_index > d->d_index) {
907 /* found a free spot! */
908 break;
909 }
910 d->d_index++;
911 }
912 /*
913 * NB: If srch is NULL, then list_insert_before puts
914 * it on the tail of the list. So if we didn't find a
915 * hole, then that's where we want it.
916 */
917 list_insert_before(l, srch, d);
918
919 /* insert in order by number */
920 l = &auimpl_devs_by_number;
921 for (srch = list_head(l); srch; srch = list_next(l, srch)) {
922 if (srch->d_number >= d->d_number) {
923 break;
924 }
925 }
926 list_insert_before(l, srch, d);
927
928 rw_exit(&auimpl_dev_lock);
929
930 if (auimpl_create_minors(d) != 0) {
931 rw_enter(&auimpl_dev_lock, RW_WRITER);
932 auimpl_remove_minors(d);
933 list_remove(&auimpl_devs_by_index, d);
934 list_remove(&auimpl_devs_by_number, d);
935 rw_exit(&auimpl_dev_lock);
936 return (DDI_FAILURE);
937 }
938
939 return (DDI_SUCCESS);
940 }
941
942 int
audio_dev_unregister(audio_dev_t * d)943 audio_dev_unregister(audio_dev_t *d)
944 {
945 rw_enter(&auimpl_dev_lock, RW_WRITER);
946
947 mutex_enter(&d->d_lock);
948 /* if we are still in use, we can't unregister */
949 if (d->d_refcnt) {
950 mutex_exit(&d->d_lock);
951 rw_exit(&auimpl_dev_lock);
952 return (DDI_FAILURE);
953 }
954 auimpl_remove_minors(d);
955 list_remove(&auimpl_devs_by_index, d);
956 list_remove(&auimpl_devs_by_number, d);
957 mutex_exit(&d->d_lock);
958
959 rw_exit(&auimpl_dev_lock);
960
961 return (DDI_SUCCESS);
962 }
963
964 static int
auimpl_engine_ksupdate(kstat_t * ksp,int rw)965 auimpl_engine_ksupdate(kstat_t *ksp, int rw)
966 {
967 audio_engine_t *e = ksp->ks_private;
968 struct audio_stats *st = &e->e_stats;
969
970 if (rw == KSTAT_WRITE) {
971 return (EACCES);
972 }
973
974 mutex_enter(&e->e_lock);
975 st->st_head.value.ui64 = e->e_head;
976 st->st_tail.value.ui64 = e->e_tail;
977 st->st_flags.value.ui32 = e->e_flags;
978 st->st_nbytes.value.ui32 = e->e_framesz * e->e_nframes;
979 st->st_framesz.value.ui32 = e->e_framesz;
980 st->st_hidx.value.ui32 = e->e_hidx;
981 st->st_tidx.value.ui32 = e->e_tidx;
982 st->st_format.value.ui32 = e->e_format;
983 st->st_nchan.value.ui32 = e->e_nchan;
984 st->st_rate.value.ui32 = e->e_rate;
985 st->st_errors.value.ui32 = e->e_errors;
986 st->st_engine_underruns.value.ui32 = e->e_underruns;
987 st->st_engine_overruns.value.ui32 = e->e_overruns;
988 st->st_stream_underruns.value.ui32 = e->e_stream_underruns;
989 st->st_stream_overruns.value.ui32 = e->e_stream_overruns;
990 st->st_suspended.value.ui32 = e->e_suspended;
991 st->st_failed.value.ui32 = e->e_failed;
992 st->st_playahead.value.ui32 = e->e_playahead;
993 mutex_exit(&e->e_lock);
994
995 return (0);
996 }
997
998 static void
auimpl_engine_ksinit(audio_dev_t * d,audio_engine_t * e)999 auimpl_engine_ksinit(audio_dev_t *d, audio_engine_t *e)
1000 {
1001 char name[32];
1002 struct audio_stats *st;
1003
1004 (void) snprintf(name, sizeof (name), "engine_%d", e->e_num);
1005
1006 e->e_ksp = kstat_create(ddi_driver_name(d->d_dip), d->d_instance,
1007 name, "misc", KSTAT_TYPE_NAMED,
1008 sizeof (struct audio_stats) / sizeof (kstat_named_t), 0);
1009
1010 if (e->e_ksp == NULL) {
1011 audio_dev_warn(d, "unable to initialize kstats");
1012 return;
1013 }
1014
1015 st = &e->e_stats;
1016 e->e_ksp->ks_data = st;
1017 e->e_ksp->ks_private = e;
1018 e->e_ksp->ks_lock = NULL;
1019 e->e_ksp->ks_update = auimpl_engine_ksupdate;
1020 kstat_named_init(&st->st_head, "head", KSTAT_DATA_UINT64);
1021 kstat_named_init(&st->st_tail, "tail", KSTAT_DATA_UINT64);
1022 kstat_named_init(&st->st_flags, "flags", KSTAT_DATA_UINT32);
1023 kstat_named_init(&st->st_nbytes, "nbytes", KSTAT_DATA_UINT32);
1024 kstat_named_init(&st->st_framesz, "framesz", KSTAT_DATA_UINT32);
1025 kstat_named_init(&st->st_hidx, "hidx", KSTAT_DATA_UINT32);
1026 kstat_named_init(&st->st_tidx, "tidx", KSTAT_DATA_UINT32);
1027 kstat_named_init(&st->st_format, "format", KSTAT_DATA_UINT32);
1028 kstat_named_init(&st->st_nchan, "channels", KSTAT_DATA_UINT32);
1029 kstat_named_init(&st->st_rate, "rate", KSTAT_DATA_UINT32);
1030 kstat_named_init(&st->st_errors, "errors", KSTAT_DATA_UINT32);
1031 kstat_named_init(&st->st_engine_overruns, "engine_overruns",
1032 KSTAT_DATA_UINT32);
1033 kstat_named_init(&st->st_engine_underruns, "engine_underruns",
1034 KSTAT_DATA_UINT32);
1035 kstat_named_init(&st->st_stream_overruns, "stream_overruns",
1036 KSTAT_DATA_UINT32);
1037 kstat_named_init(&st->st_stream_underruns, "stream_underruns",
1038 KSTAT_DATA_UINT32);
1039 kstat_named_init(&st->st_playahead, "playahead", KSTAT_DATA_UINT32);
1040 kstat_named_init(&st->st_suspended, "suspended", KSTAT_DATA_UINT32);
1041 kstat_named_init(&st->st_failed, "failed", KSTAT_DATA_UINT32);
1042 kstat_install(e->e_ksp);
1043 }
1044
1045 void
audio_dev_add_engine(audio_dev_t * d,audio_engine_t * e)1046 audio_dev_add_engine(audio_dev_t *d, audio_engine_t *e)
1047 {
1048 mutex_enter(&d->d_lock);
1049
1050 e->e_num = d->d_engno++;
1051
1052 auimpl_engine_ksinit(d, e);
1053
1054 /* check for duplex */
1055 if ((e->e_flags & ENGINE_OUTPUT_CAP) && (d->d_flags & DEV_INPUT_CAP)) {
1056 d->d_flags |= DEV_DUPLEX_CAP;
1057 }
1058 if ((e->e_flags & ENGINE_INPUT_CAP) && (d->d_flags & DEV_OUTPUT_CAP)) {
1059 d->d_flags |= DEV_DUPLEX_CAP;
1060 }
1061 /* add in the direction caps -- must be done after duplex above */
1062 if (e->e_flags & ENGINE_OUTPUT_CAP) {
1063 d->d_flags |= DEV_OUTPUT_CAP;
1064 }
1065 if (e->e_flags & ENGINE_INPUT_CAP) {
1066 d->d_flags |= DEV_INPUT_CAP;
1067 }
1068
1069 list_insert_tail(&d->d_engines, e);
1070 e->e_dev = d;
1071 mutex_exit(&d->d_lock);
1072 }
1073
1074 void
audio_dev_remove_engine(audio_dev_t * d,audio_engine_t * e)1075 audio_dev_remove_engine(audio_dev_t *d, audio_engine_t *e)
1076 {
1077 mutex_enter(&d->d_lock);
1078 list_remove(&d->d_engines, e);
1079 e->e_dev = NULL;
1080 if (e->e_ksp)
1081 kstat_delete(e->e_ksp);
1082 e->e_ksp = NULL;
1083 mutex_exit(&d->d_lock);
1084 }
1085
1086 /*
1087 * Change the number.
1088 */
1089 void
auclnt_set_dev_number(audio_dev_t * d,int num)1090 auclnt_set_dev_number(audio_dev_t *d, int num)
1091 {
1092 list_t *l = &auimpl_devs_by_number;
1093 audio_dev_t *srch;
1094
1095 /* reorder our list */
1096 rw_enter(&auimpl_dev_lock, RW_WRITER);
1097 d->d_number = num;
1098 list_remove(l, d);
1099 for (srch = list_head(l); srch; srch = list_next(l, srch)) {
1100 if (srch->d_number >= d->d_number) {
1101 break;
1102 }
1103 }
1104 list_insert_before(l, srch, d);
1105
1106 rw_exit(&auimpl_dev_lock);
1107 }
1108
1109 void
auclnt_walk_devs(int (* walker)(audio_dev_t *,void *),void * arg)1110 auclnt_walk_devs(int (*walker)(audio_dev_t *, void *), void *arg)
1111 {
1112 audio_dev_t *d;
1113 boolean_t cont;
1114 list_t *l;
1115
1116 l = &auimpl_devs_by_index;
1117 rw_enter(&auimpl_dev_lock, RW_READER);
1118 for (d = list_head(l); d; d = list_next(l, d)) {
1119 cont = walker(d, arg);
1120 if (cont == AUDIO_WALK_STOP)
1121 break;
1122 }
1123 rw_exit(&auimpl_dev_lock);
1124 }
1125
1126 void
auclnt_walk_devs_by_number(int (* walker)(audio_dev_t *,void *),void * arg)1127 auclnt_walk_devs_by_number(int (*walker)(audio_dev_t *, void *), void *arg)
1128 {
1129 audio_dev_t *d;
1130 boolean_t cont;
1131 list_t *l;
1132
1133 l = &auimpl_devs_by_number;
1134 rw_enter(&auimpl_dev_lock, RW_READER);
1135 for (d = list_head(l); d; d = list_next(l, d)) {
1136 cont = walker(d, arg);
1137 if (cont == AUDIO_WALK_STOP)
1138 break;
1139 }
1140 rw_exit(&auimpl_dev_lock);
1141 }
1142
1143 void
auclnt_dev_walk_engines(audio_dev_t * d,int (* walker)(audio_engine_t *,void *),void * arg)1144 auclnt_dev_walk_engines(audio_dev_t *d,
1145 int (*walker)(audio_engine_t *, void *),
1146 void *arg)
1147 {
1148 audio_engine_t *e;
1149 list_t *l = &d->d_engines;
1150
1151 mutex_enter(&d->d_lock);
1152 for (e = list_head(l); e != NULL; e = list_next(l, e)) {
1153 if (walker(e, arg) == AUDIO_WALK_STOP) {
1154 break;
1155 }
1156 }
1157 mutex_exit(&d->d_lock);
1158 }
1159
1160 int
auclnt_engine_get_format(audio_engine_t * e)1161 auclnt_engine_get_format(audio_engine_t *e)
1162 {
1163 return (ENG_FORMAT(e));
1164 }
1165
1166 int
auclnt_engine_get_channels(audio_engine_t * e)1167 auclnt_engine_get_channels(audio_engine_t *e)
1168 {
1169 return (ENG_CHANNELS(e));
1170 }
1171
1172 int
auclnt_engine_get_rate(audio_engine_t * e)1173 auclnt_engine_get_rate(audio_engine_t *e)
1174 {
1175 return (ENG_RATE(e));
1176 }
1177
1178 uint_t
auclnt_engine_get_capab(audio_engine_t * e)1179 auclnt_engine_get_capab(audio_engine_t *e)
1180 {
1181 uint_t capab = 0;
1182
1183 if (e->e_flags & ENGINE_INPUT_CAP) {
1184 capab |= AUDIO_CLIENT_CAP_RECORD;
1185 }
1186 if (e->e_flags & ENGINE_OUTPUT_CAP) {
1187 capab |= AUDIO_CLIENT_CAP_PLAY;
1188 }
1189 return (capab);
1190 }
1191
1192 /*
1193 * This function suspends an engine. The intent is to pause the
1194 * engine temporarily so that it does not underrun while user threads
1195 * are suspended. The driver is still responsible for actually doing
1196 * the driver suspend work -- all this does is put the engine in a
1197 * paused state. It does not prevent, for example, threads from
1198 * accessing the hardware.
1199 *
1200 * A properly implemented driver won't even be aware of the existence
1201 * of this routine -- the driver will just handle the suspend &
1202 * resume. At the point of suspend & resume, the driver will see that
1203 * the engines are not running (as if all threads had "paused" it).
1204 *
1205 * Failure to execute either of the routines below is not critical,
1206 * but will probably lead to underruns and overflows as the kernel
1207 * driver gets resumed well in advance of the time when user threads
1208 * are ready to start operation.
1209 */
1210 static void
auimpl_engine_suspend(audio_engine_t * e)1211 auimpl_engine_suspend(audio_engine_t *e)
1212 {
1213 ASSERT(mutex_owned(&e->e_lock));
1214
1215 if (e->e_failed || e->e_suspended) {
1216 e->e_suspended = B_TRUE;
1217 return;
1218 }
1219 e->e_suspended = B_TRUE;
1220 if (e->e_flags & ENGINE_INPUT) {
1221 e->e_head = ENG_COUNT(e);
1222 ENG_STOP(e);
1223 }
1224 if (e->e_flags & ENGINE_OUTPUT) {
1225 e->e_tail = ENG_COUNT(e);
1226 ENG_STOP(e);
1227 }
1228 }
1229
1230 static void
auimpl_engine_resume(audio_engine_t * e)1231 auimpl_engine_resume(audio_engine_t *e)
1232 {
1233 ASSERT(mutex_owned(&e->e_lock));
1234 ASSERT(e->e_suspended);
1235
1236 if (e->e_failed) {
1237 /* No longer suspended, but still failed! */
1238 e->e_suspended = B_FALSE;
1239 return;
1240 }
1241
1242 if (e->e_flags & (ENGINE_INPUT | ENGINE_OUTPUT)) {
1243
1244 auimpl_engine_reset(e);
1245
1246 if (e->e_flags & ENGINE_OUTPUT) {
1247 auimpl_output_preload(e);
1248 }
1249
1250 e->e_need_start = B_TRUE;
1251 }
1252 e->e_suspended = B_FALSE;
1253 cv_broadcast(&e->e_cv);
1254 }
1255
1256 static int
auimpl_dev_suspend(audio_dev_t * d,void * dontcare)1257 auimpl_dev_suspend(audio_dev_t *d, void *dontcare)
1258 {
1259 list_t *l;
1260 audio_engine_t *e;
1261
1262 _NOTE(ARGUNUSED(dontcare));
1263
1264 mutex_enter(&d->d_lock);
1265 mutex_enter(&d->d_ctrl_lock);
1266 if (d->d_suspended) {
1267 d->d_suspended++;
1268 mutex_exit(&d->d_ctrl_lock);
1269 mutex_exit(&d->d_lock);
1270 return (AUDIO_WALK_CONTINUE);
1271 }
1272
1273 d->d_suspended++;
1274
1275 (void) auimpl_save_controls(d);
1276 mutex_exit(&d->d_ctrl_lock);
1277
1278 l = &d->d_engines;
1279 for (e = list_head(l); e != NULL; e = list_next(l, e)) {
1280 mutex_enter(&e->e_lock);
1281 auimpl_engine_suspend(e);
1282 mutex_exit(&e->e_lock);
1283 }
1284 mutex_exit(&d->d_lock);
1285
1286 return (AUDIO_WALK_CONTINUE);
1287 }
1288
1289 static int
auimpl_dev_resume(audio_dev_t * d,void * dontcare)1290 auimpl_dev_resume(audio_dev_t *d, void *dontcare)
1291 {
1292 list_t *l;
1293 audio_engine_t *e;
1294
1295 _NOTE(ARGUNUSED(dontcare));
1296
1297 mutex_enter(&d->d_lock);
1298 mutex_enter(&d->d_ctrl_lock);
1299
1300 ASSERT(d->d_suspended);
1301 d->d_suspended--;
1302 if (d->d_suspended) {
1303 mutex_exit(&d->d_ctrl_lock);
1304 mutex_exit(&d->d_lock);
1305 return (AUDIO_WALK_CONTINUE);
1306 }
1307
1308 (void) auimpl_restore_controls(d);
1309 cv_broadcast(&d->d_ctrl_cv);
1310 mutex_exit(&d->d_ctrl_lock);
1311
1312 l = &d->d_engines;
1313 for (e = list_head(l); e != NULL; e = list_next(l, e)) {
1314 mutex_enter(&e->e_lock);
1315 auimpl_engine_resume(e);
1316 mutex_exit(&e->e_lock);
1317 }
1318 mutex_exit(&d->d_lock);
1319
1320 return (AUDIO_WALK_CONTINUE);
1321 }
1322
1323 boolean_t
auimpl_cpr(void * arg,int code)1324 auimpl_cpr(void *arg, int code)
1325 {
1326 _NOTE(ARGUNUSED(arg));
1327
1328 switch (code) {
1329 case CB_CODE_CPR_CHKPT:
1330 auclnt_walk_devs(auimpl_dev_suspend, NULL);
1331 return (B_TRUE);
1332
1333 case CB_CODE_CPR_RESUME:
1334 auclnt_walk_devs(auimpl_dev_resume, NULL);
1335 return (B_TRUE);
1336
1337 default:
1338 return (B_FALSE);
1339 }
1340 }
1341
1342 void
audio_dev_suspend(audio_dev_t * d)1343 audio_dev_suspend(audio_dev_t *d)
1344 {
1345 (void) auimpl_dev_suspend(d, NULL);
1346 }
1347
1348 void
audio_dev_resume(audio_dev_t * d)1349 audio_dev_resume(audio_dev_t *d)
1350 {
1351 (void) auimpl_dev_resume(d, NULL);
1352 }
1353
1354 static callb_id_t auimpl_cpr_id = 0;
1355
1356 void
auimpl_dev_init(void)1357 auimpl_dev_init(void)
1358 {
1359 rw_init(&auimpl_dev_lock, NULL, RW_DRIVER, NULL);
1360 list_create(&auimpl_devs_by_index, sizeof (struct audio_dev),
1361 offsetof(struct audio_dev, d_by_index));
1362 list_create(&auimpl_devs_by_number, sizeof (struct audio_dev),
1363 offsetof(struct audio_dev, d_by_number));
1364
1365 /*
1366 * We "borrow" the CB_CL_CPR_PM class, which gets executed at
1367 * about the right time for us. It would be nice to have a
1368 * new CB_CL_CPR_AUDIO class, but it isn't critical at this
1369 * point.
1370 *
1371 * Note that we don't care about our thread id.
1372 */
1373 auimpl_cpr_id = callb_add(auimpl_cpr, NULL, CB_CL_CPR_PM, "audio_cpr");
1374 }
1375
1376 void
auimpl_dev_fini(void)1377 auimpl_dev_fini(void)
1378 {
1379 (void) callb_delete(auimpl_cpr_id);
1380 list_destroy(&auimpl_devs_by_index);
1381 list_destroy(&auimpl_devs_by_number);
1382 rw_destroy(&auimpl_dev_lock);
1383 }
1384
1385 void
audio_engine_set_private(audio_engine_t * eng,void * prv)1386 audio_engine_set_private(audio_engine_t *eng, void *prv)
1387 {
1388 eng->e_private = prv;
1389 }
1390
1391 void *
audio_engine_get_private(audio_engine_t * eng)1392 audio_engine_get_private(audio_engine_t *eng)
1393 {
1394 return (eng->e_private);
1395 }
1396
1397 void
audio_dump_bytes(const uint8_t * w,int dcount)1398 audio_dump_bytes(const uint8_t *w, int dcount)
1399 {
1400 char line[64];
1401 char *s;
1402 int i;
1403 const int wrap = 16;
1404
1405 s = line;
1406 line[0] = 0;
1407
1408 cmn_err(CE_NOTE, "starting @ %p", (void *)w);
1409 for (i = 0; i < dcount; i++) {
1410
1411 (void) sprintf(s, " %02x", *w);
1412 s += strlen(s);
1413 w++;
1414
1415 if ((i % wrap) == (wrap - 1)) {
1416 cmn_err(CE_NOTE, "%08x:%s", i - (wrap - 1), line);
1417 line[0] = 0;
1418 s = line;
1419 }
1420 }
1421
1422 if ((i % wrap) != 0) {
1423 cmn_err(CE_NOTE, "%08x:%s", i - (i % wrap), line);
1424 }
1425 }
1426
1427 void
audio_dump_words(const uint16_t * w,int dcount)1428 audio_dump_words(const uint16_t *w, int dcount)
1429 {
1430 char line[64];
1431 char *s;
1432 int i;
1433 const int wrap = 8;
1434
1435 s = line;
1436 line[0] = 0;
1437
1438 cmn_err(CE_NOTE, "starting @ %p", (void *)w);
1439 for (i = 0; i < dcount; i++) {
1440
1441 (void) sprintf(s, " %04x", *w);
1442 s += strlen(s);
1443 w++;
1444
1445 if ((i % wrap) == (wrap - 1)) {
1446 cmn_err(CE_NOTE, "%08x:%s", i - (wrap - 1), line);
1447 line[0] = 0;
1448 s = line;
1449 }
1450 }
1451
1452 if ((i % wrap) != 0) {
1453 cmn_err(CE_NOTE, "%08x:%s", i - (i % wrap), line);
1454 }
1455 }
1456
1457 void
audio_dump_dwords(const uint32_t * w,int dcount)1458 audio_dump_dwords(const uint32_t *w, int dcount)
1459 {
1460 char line[128];
1461 char *s;
1462 int i;
1463 const int wrap = 4;
1464
1465 s = line;
1466 line[0] = 0;
1467
1468 cmn_err(CE_NOTE, "starting @ %p", (void *)w);
1469 for (i = 0; i < dcount; i++) {
1470
1471 (void) sprintf(s, " %08x", *w);
1472 s += strlen(s);
1473 w++;
1474
1475 if ((i % wrap) == (wrap - 1)) {
1476 cmn_err(CE_NOTE, "%08x:%s", i - (wrap - 1), line);
1477 line[0] = 0;
1478 s = line;
1479 }
1480 }
1481
1482 if ((i % wrap) != 0) {
1483 cmn_err(CE_NOTE, "%08x:%s", i - (i % wrap), line);
1484 }
1485 }
1486