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