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 * 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 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 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 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 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 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 * 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1161 auclnt_engine_get_format(audio_engine_t *e) 1162 { 1163 return (ENG_FORMAT(e)); 1164 } 1165 1166 int 1167 auclnt_engine_get_channels(audio_engine_t *e) 1168 { 1169 return (ENG_CHANNELS(e)); 1170 } 1171 1172 int 1173 auclnt_engine_get_rate(audio_engine_t *e) 1174 { 1175 return (ENG_RATE(e)); 1176 } 1177 1178 uint_t 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 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 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 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 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 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 1343 audio_dev_suspend(audio_dev_t *d) 1344 { 1345 (void) auimpl_dev_suspend(d, NULL); 1346 } 1347 1348 void 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 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 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 1386 audio_engine_set_private(audio_engine_t *eng, void *prv) 1387 { 1388 eng->e_private = prv; 1389 } 1390 1391 void * 1392 audio_engine_get_private(audio_engine_t *eng) 1393 { 1394 return (eng->e_private); 1395 } 1396 1397 void 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 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 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