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 * 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 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 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 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 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 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 * 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1155 auclnt_engine_get_format(audio_engine_t *e) 1156 { 1157 return (ENG_FORMAT(e)); 1158 } 1159 1160 int 1161 auclnt_engine_get_channels(audio_engine_t *e) 1162 { 1163 return (ENG_CHANNELS(e)); 1164 } 1165 1166 int 1167 auclnt_engine_get_rate(audio_engine_t *e) 1168 { 1169 return (ENG_RATE(e)); 1170 } 1171 1172 uint_t 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 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 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 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 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 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 1337 audio_dev_suspend(audio_dev_t *d) 1338 { 1339 (void) auimpl_dev_suspend(d, NULL); 1340 } 1341 1342 void 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 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 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 1380 audio_engine_set_private(audio_engine_t *eng, void *prv) 1381 { 1382 eng->e_private = prv; 1383 } 1384 1385 void * 1386 audio_engine_get_private(audio_engine_t *eng) 1387 { 1388 return (eng->e_private); 1389 } 1390 1391 void 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 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 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