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 2010 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/sysmacros.h> 30 #include <sys/list.h> 31 #include <sys/file.h> 32 #include <sys/open.h> 33 #include <sys/stat.h> 34 #include <sys/errno.h> 35 #include <sys/atomic.h> 36 #include <sys/ddi.h> 37 #include <sys/sunddi.h> 38 39 #include "audio_impl.h" 40 41 /* 42 * Audio Client implementation. 43 */ 44 45 /* 46 * Attenuation table for dB->linear conversion. Indexed in steps of 47 * 0.5 dB. Table size is 25 dB (first entry is handled as mute). 48 * 49 * Notably, the last item in table is taken as 0 dB (i.e. maximum volume). 50 * 51 * Table contents can be calculated as follows (requires sunmath library): 52 * 53 * scale = AUDIO_VOL_SCALE; 54 * for (i = -50; i <= 0; i++) { 55 * x = exp10(0.05 * i); 56 * printf("%d: %f %.0f\n", i, x, trunc(x * scale)); 57 * } 58 * 59 */ 60 61 static const uint16_t auimpl_db_table[AUDIO_DB_SIZE + 1] = { 62 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 63 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 64 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 65 25, 28, 32, 36, 40, 45, 51, 57, 64, 72, 66 80, 90, 101, 114, 128, 143, 161, 181, 203, 228, 67 256 68 }; 69 70 static list_t auimpl_clients; 71 static krwlock_t auimpl_client_lock; 72 static audio_client_ops_t *audio_client_ops[AUDIO_MN_TYPE_MASK + 1]; 73 74 void * 75 auclnt_get_private(audio_client_t *c) 76 { 77 return (c->c_private); 78 } 79 80 void 81 auclnt_set_private(audio_client_t *c, void *private) 82 { 83 c->c_private = private; 84 } 85 86 int 87 auclnt_set_rate(audio_stream_t *sp, int rate) 88 { 89 audio_parms_t parms; 90 int rv = 0; 91 92 /* basic sanity checks! */ 93 if ((rate < 5000) || (rate > 192000)) { 94 return (EINVAL); 95 } 96 mutex_enter(&sp->s_lock); 97 parms = *sp->s_user_parms; 98 if (rate != parms.p_rate) { 99 parms.p_rate = rate; 100 rv = auimpl_format_setup(sp, &parms); 101 } 102 mutex_exit(&sp->s_lock); 103 return (rv); 104 } 105 106 int 107 auclnt_get_rate(audio_stream_t *sp) 108 { 109 return (sp->s_user_parms->p_rate); 110 } 111 112 uint_t 113 auclnt_get_fragsz(audio_stream_t *sp) 114 { 115 return (sp->s_fragbytes); 116 } 117 118 uint_t 119 auclnt_get_framesz(audio_stream_t *sp) 120 { 121 return (sp->s_framesz); 122 } 123 124 uint_t 125 auclnt_get_nfrags(audio_stream_t *sp) 126 { 127 return (sp->s_nfrags); 128 } 129 130 uint_t 131 auclnt_get_nframes(audio_stream_t *sp) 132 { 133 return (sp->s_nframes); 134 } 135 136 void 137 auclnt_set_latency(audio_stream_t *sp, uint_t frags, uint_t bytes) 138 { 139 mutex_enter(&sp->s_lock); 140 sp->s_hintfrags = (uint16_t)frags; 141 sp->s_hintsz = bytes; 142 mutex_exit(&sp->s_lock); 143 } 144 145 uint64_t 146 auclnt_get_head(audio_stream_t *sp) 147 { 148 return (sp->s_head); 149 } 150 151 uint64_t 152 auclnt_get_tail(audio_stream_t *sp) 153 { 154 return (sp->s_tail); 155 } 156 157 uint_t 158 auclnt_get_hidx(audio_stream_t *sp) 159 { 160 return (sp->s_hidx); 161 } 162 163 uint_t 164 auclnt_get_tidx(audio_stream_t *sp) 165 { 166 return (sp->s_tidx); 167 } 168 169 audio_stream_t * 170 auclnt_input_stream(audio_client_t *c) 171 { 172 return (&c->c_istream); 173 } 174 175 audio_stream_t * 176 auclnt_output_stream(audio_client_t *c) 177 { 178 return (&c->c_ostream); 179 } 180 181 uint_t 182 auclnt_get_count(audio_stream_t *sp) 183 { 184 uint_t count; 185 186 mutex_enter(&sp->s_lock); 187 ASSERT((sp->s_head - sp->s_tail) <= sp->s_nframes); 188 count = (uint_t)(sp->s_head - sp->s_tail); 189 mutex_exit(&sp->s_lock); 190 191 return (count); 192 } 193 194 uint_t 195 auclnt_consume(audio_stream_t *sp, uint_t n) 196 { 197 mutex_enter(&sp->s_lock); 198 199 ASSERT(sp == &sp->s_client->c_istream); 200 n = max(n, sp->s_head - sp->s_tail); 201 sp->s_tail += n; 202 sp->s_tidx += n; 203 if (sp->s_tidx >= sp->s_nframes) { 204 sp->s_tidx -= sp->s_nframes; 205 } 206 207 ASSERT(sp->s_tail <= sp->s_head); 208 ASSERT(sp->s_hidx < sp->s_nframes); 209 210 mutex_exit(&sp->s_lock); 211 212 return (n); 213 } 214 215 uint_t 216 auclnt_consume_data(audio_stream_t *sp, caddr_t dst, uint_t n) 217 { 218 uint_t nframes; 219 uint_t framesz; 220 uint_t cnt; 221 caddr_t data; 222 223 mutex_enter(&sp->s_lock); 224 225 nframes = sp->s_nframes; 226 framesz = sp->s_framesz; 227 228 ASSERT(sp == &sp->s_client->c_istream); 229 ASSERT(sp->s_head >= sp->s_tail); 230 ASSERT(sp->s_tidx < nframes); 231 ASSERT(sp->s_hidx < nframes); 232 233 cnt = n = min(n, sp->s_head - sp->s_tail); 234 data = sp->s_data + (sp->s_tidx * framesz); 235 do { 236 uint_t nf, nb; 237 238 nf = min(nframes - sp->s_tidx, n); 239 nb = nf * framesz; 240 241 bcopy(data, dst, nb); 242 dst += nb; 243 data += nb; 244 245 n -= nf; 246 sp->s_tail += nf; 247 sp->s_tidx += nf; 248 if (sp->s_tidx == nframes) { 249 sp->s_tidx = 0; 250 data = sp->s_data; 251 } 252 } while (n); 253 254 ASSERT(sp->s_tail <= sp->s_head); 255 ASSERT(sp->s_tidx < nframes); 256 257 mutex_exit(&sp->s_lock); 258 259 return (cnt); 260 } 261 262 uint_t 263 auclnt_produce(audio_stream_t *sp, uint_t n) 264 { 265 mutex_enter(&sp->s_lock); 266 267 ASSERT(sp == &sp->s_client->c_ostream); 268 n = max(n, sp->s_nframes - (sp->s_head - sp->s_tail)); 269 sp->s_head += n; 270 sp->s_hidx += n; 271 if (sp->s_hidx >= sp->s_nframes) { 272 sp->s_hidx -= sp->s_nframes; 273 } 274 275 ASSERT(sp->s_tail <= sp->s_head); 276 ASSERT(sp->s_hidx < sp->s_nframes); 277 278 mutex_exit(&sp->s_lock); 279 280 return (n); 281 } 282 283 uint_t 284 auclnt_produce_data(audio_stream_t *sp, caddr_t src, uint_t n) 285 { 286 uint_t nframes; 287 uint_t framesz; 288 uint_t cnt; 289 caddr_t data; 290 291 mutex_enter(&sp->s_lock); 292 293 nframes = sp->s_nframes; 294 framesz = sp->s_framesz; 295 296 ASSERT(sp == &sp->s_client->c_ostream); 297 ASSERT(sp->s_head >= sp->s_tail); 298 ASSERT(sp->s_tidx < nframes); 299 ASSERT(sp->s_hidx < nframes); 300 301 cnt = n = min(n, nframes - (sp->s_head - sp->s_tail)); 302 data = sp->s_data + (sp->s_hidx * framesz); 303 do { 304 uint_t nf, nb; 305 306 nf = min(nframes - sp->s_hidx, n); 307 nb = nf * framesz; 308 309 bcopy(src, data, nb); 310 311 src += nb; 312 data += nb; 313 314 n -= nf; 315 sp->s_head += nf; 316 sp->s_hidx += nf; 317 if (sp->s_hidx == nframes) { 318 sp->s_hidx = 0; 319 data = sp->s_data; 320 } 321 } while (n); 322 323 ASSERT(sp->s_tail <= sp->s_head); 324 ASSERT(sp->s_hidx < nframes); 325 326 mutex_exit(&sp->s_lock); 327 328 return (cnt); 329 } 330 331 int 332 auclnt_read(audio_client_t *c, struct uio *uio) 333 { 334 audio_stream_t *sp = &c->c_istream; 335 uint_t cnt; 336 int rv = 0; 337 offset_t loff; 338 int eagain; 339 uint_t tidx; 340 uint_t framesz; 341 342 loff = uio->uio_loffset; 343 eagain = EAGAIN; 344 345 mutex_enter(&sp->s_lock); 346 347 if ((!sp->s_paused) && (!sp->s_running)) { 348 mutex_exit(&sp->s_lock); 349 auclnt_start(sp); 350 mutex_enter(&sp->s_lock); 351 } 352 353 354 framesz = sp->s_framesz; 355 356 ASSERT(sp->s_head >= sp->s_tail); 357 ASSERT(sp->s_tidx < sp->s_nframes); 358 359 while (uio->uio_resid >= framesz) { 360 361 while ((cnt = (sp->s_head - sp->s_tail)) == 0) { 362 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) { 363 mutex_exit(&sp->s_lock); 364 return (eagain); 365 } 366 if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) { 367 mutex_exit(&sp->s_lock); 368 return (EINTR); 369 } 370 } 371 372 tidx = sp->s_tidx; 373 cnt = min(cnt, sp->s_nframes - tidx); 374 cnt = min(cnt, (uio->uio_resid / framesz)); 375 376 mutex_exit(&sp->s_lock); 377 rv = uiomove(sp->s_data + (tidx * framesz), 378 cnt * framesz, UIO_READ, uio); 379 380 uio->uio_loffset = loff; 381 eagain = 0; 382 383 if (rv != 0) { 384 return (rv); 385 } 386 387 mutex_enter(&sp->s_lock); 388 sp->s_tail += cnt; 389 sp->s_tidx += cnt; 390 if (sp->s_tidx == sp->s_nframes) { 391 sp->s_tidx = 0; 392 } 393 } 394 395 ASSERT(sp->s_tail <= sp->s_head); 396 ASSERT(sp->s_tidx < sp->s_nframes); 397 398 /* round off any remaining partial bits */ 399 uio->uio_resid = 0; 400 401 mutex_exit(&sp->s_lock); 402 403 return (rv); 404 } 405 406 int 407 auclnt_write(audio_client_t *c, struct uio *uio) 408 { 409 audio_stream_t *sp = &c->c_ostream; 410 uint_t cnt; 411 int rv = 0; 412 offset_t loff; 413 int eagain; 414 uint_t framesz; 415 uint_t hidx; 416 417 loff = uio->uio_loffset; 418 eagain = EAGAIN; 419 420 mutex_enter(&sp->s_lock); 421 422 framesz = sp->s_framesz; 423 424 ASSERT(sp->s_head >= sp->s_tail); 425 ASSERT(sp->s_hidx < sp->s_nframes); 426 427 while (uio->uio_resid >= framesz) { 428 429 while ((cnt = sp->s_nframes - (sp->s_head - sp->s_tail)) == 0) { 430 if (uio->uio_fmode & (FNONBLOCK|FNDELAY)) { 431 mutex_exit(&sp->s_lock); 432 return (eagain); 433 } 434 if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) { 435 mutex_exit(&sp->s_lock); 436 return (EINTR); 437 } 438 } 439 440 hidx = sp->s_hidx; 441 cnt = min(cnt, sp->s_nframes - hidx); 442 cnt = min(cnt, (uio->uio_resid / framesz)); 443 444 /* 445 * We have to drop the stream lock, because the 446 * uiomove might require doing a page in, which could 447 * get blocked behind the PIL of the audio processing 448 * thread which also grabs the s_lock. (Hence, there 449 * is a risk of deadlock due to priority inversion.) 450 */ 451 mutex_exit(&sp->s_lock); 452 453 rv = uiomove(sp->s_data + (hidx * framesz), 454 cnt * framesz, UIO_WRITE, uio); 455 456 uio->uio_loffset = loff; 457 eagain = 0; 458 459 if (rv != 0) { 460 return (rv); 461 } 462 463 mutex_enter(&sp->s_lock); 464 465 sp->s_head += cnt; 466 sp->s_hidx += cnt; 467 if (sp->s_hidx == sp->s_nframes) { 468 sp->s_hidx = 0; 469 } 470 471 if ((!sp->s_paused) && (!sp->s_running) && 472 ((sp->s_head - sp->s_tail) > sp->s_fragfr)) { 473 mutex_exit(&sp->s_lock); 474 auclnt_start(sp); 475 mutex_enter(&sp->s_lock); 476 } 477 } 478 479 ASSERT(sp->s_tail <= sp->s_head); 480 ASSERT(sp->s_hidx < sp->s_nframes); 481 482 /* round off any remaining partial bits */ 483 uio->uio_resid = 0; 484 485 mutex_exit(&sp->s_lock); 486 487 return (rv); 488 } 489 490 int 491 auclnt_chpoll(audio_client_t *c, short events, int anyyet, short *reventsp, 492 struct pollhead **phpp) 493 { 494 audio_stream_t *sp; 495 short nev = 0; 496 497 if (events & (POLLIN | POLLRDNORM)) { 498 sp = &c->c_istream; 499 mutex_enter(&sp->s_lock); 500 if ((sp->s_head - sp->s_tail) > sp->s_fragfr) { 501 nev = POLLIN | POLLRDNORM; 502 } 503 mutex_exit(&sp->s_lock); 504 } 505 506 if (events & POLLOUT) { 507 sp = &c->c_ostream; 508 mutex_enter(&sp->s_lock); 509 if ((sp->s_nframes - (sp->s_head - sp->s_tail)) > 510 sp->s_fragfr) { 511 nev = POLLOUT; 512 } 513 mutex_exit(&sp->s_lock); 514 } 515 516 if (nev) { 517 *reventsp = nev & events; 518 } else { 519 *reventsp = 0; 520 if (!anyyet) { 521 *phpp = &c->c_pollhead; 522 } 523 } 524 return (0); 525 } 526 527 void 528 auclnt_pollwakeup(audio_client_t *c, short events) 529 { 530 pollwakeup(&c->c_pollhead, events); 531 } 532 533 void 534 auclnt_get_output_qlen(audio_client_t *c, uint_t *slen, uint_t *flen) 535 { 536 audio_stream_t *sp = &c->c_ostream; 537 audio_engine_t *e = sp->s_engine; 538 uint64_t el, sl; 539 uint_t cnt, er, sr; 540 541 if (e == NULL) { 542 /* if no output engine, can't do it! */ 543 *slen = 0; 544 *flen = 0; 545 return; 546 } 547 548 mutex_enter(&e->e_lock); 549 mutex_enter(&sp->s_lock); 550 if (e->e_ops.audio_engine_qlen != NULL) { 551 el = ENG_QLEN(e) + (e->e_head - e->e_tail); 552 } else { 553 el = (e->e_head - e->e_tail); 554 } 555 er = e->e_rate; 556 sl = sp->s_cnv_cnt; 557 sr = sp->s_user_parms->p_rate; 558 cnt = (uint_t)(sp->s_head - sp->s_tail); 559 mutex_exit(&sp->s_lock); 560 mutex_exit(&e->e_lock); 561 562 /* engine frames converted to stream rate, plus stream frames */ 563 *slen = cnt; 564 *flen = ((uint_t)(((el * sr) / er) + sl)); 565 } 566 567 int 568 auclnt_set_format(audio_stream_t *sp, int fmt) 569 { 570 audio_parms_t parms; 571 int rv = 0; 572 573 /* 574 * AC3: If we select an AC3 format, then we have to allocate 575 * another engine. Normally this will be an output only 576 * engine. However, for now we aren't supporting AC3 577 * passthru. 578 */ 579 580 switch (fmt) { 581 case AUDIO_FORMAT_U8: 582 case AUDIO_FORMAT_ULAW: 583 case AUDIO_FORMAT_ALAW: 584 case AUDIO_FORMAT_S8: 585 case AUDIO_FORMAT_S16_LE: 586 case AUDIO_FORMAT_S16_BE: 587 case AUDIO_FORMAT_U16_LE: 588 case AUDIO_FORMAT_U16_BE: 589 case AUDIO_FORMAT_S24_LE: 590 case AUDIO_FORMAT_S24_BE: 591 case AUDIO_FORMAT_S32_LE: 592 case AUDIO_FORMAT_S32_BE: 593 case AUDIO_FORMAT_S24_PACKED: 594 break; 595 596 case AUDIO_FORMAT_AC3: /* AC3: PASSTHRU */ 597 default: 598 return (ENOTSUP); 599 } 600 601 602 mutex_enter(&sp->s_lock); 603 parms = *sp->s_user_parms; 604 605 /* 606 * Optimization. Some personalities send us the same format 607 * over and over again. (Sun personality does this 608 * repeatedly.) setup_src is potentially expensive, so we 609 * avoid doing it unless we really need to. 610 */ 611 if (fmt != parms.p_format) { 612 /* 613 * Note that setting the format doesn't check that the 614 * audio streams have been paused. As a result, any 615 * data still playing or recording will probably get 616 * misinterpreted. It would be smart if the client 617 * application paused/stopped playback before changing 618 * formats. 619 */ 620 parms.p_format = fmt; 621 rv = auimpl_format_setup(sp, &parms); 622 } 623 mutex_exit(&sp->s_lock); 624 625 return (rv); 626 } 627 628 int 629 auclnt_get_format(audio_stream_t *sp) 630 { 631 return (sp->s_user_parms->p_format); 632 } 633 634 int 635 auclnt_get_output_format(audio_client_t *c) 636 { 637 return (c->c_ostream.s_user_parms->p_format); 638 } 639 640 int 641 auclnt_get_input_format(audio_client_t *c) 642 { 643 return (c->c_istream.s_user_parms->p_format); 644 } 645 646 int 647 auclnt_set_channels(audio_stream_t *sp, int nchan) 648 { 649 audio_parms_t parms; 650 int rv = 0; 651 652 /* Validate setting */ 653 if ((nchan > AUDIO_MAX_CHANNELS) || (nchan < 1)) { 654 return (EINVAL); 655 } 656 657 mutex_enter(&sp->s_lock); 658 parms = *sp->s_user_parms; 659 if (nchan != parms.p_nchan) { 660 parms.p_nchan = nchan; 661 rv = auimpl_format_setup(sp, &parms); 662 } 663 mutex_exit(&sp->s_lock); 664 665 return (rv); 666 } 667 668 int 669 auclnt_get_channels(audio_stream_t *sp) 670 { 671 return (sp->s_user_parms->p_nchan); 672 } 673 674 675 static void 676 auimpl_set_gain_master(audio_stream_t *sp, uint8_t gain) 677 { 678 uint32_t scaled; 679 680 if (gain > 100) { 681 gain = 0; 682 } 683 684 mutex_enter(&sp->s_lock); 685 if (sp->s_gain_master == gain) { 686 mutex_exit(&sp->s_lock); 687 return; 688 } 689 690 /* 691 * calculate the scaled values. Done now to avoid calculations 692 * later. 693 */ 694 scaled = (gain * sp->s_gain_pct * AUDIO_DB_SIZE) / (100 * 100); 695 696 sp->s_gain_master = gain; 697 sp->s_gain_scaled = auimpl_db_table[scaled]; 698 699 if (!sp->s_muted) { 700 sp->s_gain_eff = sp->s_gain_scaled; 701 } 702 mutex_exit(&sp->s_lock); 703 } 704 705 int 706 auimpl_set_pcmvol(void *arg, uint64_t val) 707 { 708 audio_dev_t *d = arg; 709 list_t *l = &d->d_clients; 710 audio_client_t *c; 711 712 if (val > 100) { 713 return (EINVAL); 714 } 715 rw_enter(&auimpl_client_lock, RW_WRITER); 716 d->d_pcmvol = val & 0xff; 717 rw_downgrade(&auimpl_client_lock); 718 719 for (c = list_head(l); c; c = list_next(l, c)) { 720 /* don't need to check is_active here, its safe */ 721 auimpl_set_gain_master(&c->c_ostream, (uint8_t)val); 722 } 723 rw_exit(&auimpl_client_lock); 724 725 return (0); 726 } 727 728 int 729 auimpl_get_pcmvol(void *arg, uint64_t *val) 730 { 731 audio_dev_t *d = arg; 732 733 *val = d->d_pcmvol; 734 return (0); 735 } 736 737 void 738 auclnt_set_gain(audio_stream_t *sp, uint8_t gain) 739 { 740 uint32_t scaled; 741 742 if (gain > 100) { 743 gain = 0; 744 } 745 746 mutex_enter(&sp->s_lock); 747 748 /* if no change, don't bother doing updates */ 749 if (sp->s_gain_pct == gain) { 750 mutex_exit(&sp->s_lock); 751 return; 752 } 753 754 /* 755 * calculate the scaled values. Done now to avoid calculations 756 * later. 757 */ 758 scaled = (gain * sp->s_gain_master * AUDIO_DB_SIZE) / (100 * 100); 759 760 sp->s_gain_pct = gain; 761 sp->s_gain_scaled = auimpl_db_table[scaled]; 762 763 if (!sp->s_muted) { 764 sp->s_gain_eff = sp->s_gain_scaled; 765 } 766 mutex_exit(&sp->s_lock); 767 768 atomic_inc_uint(&sp->s_client->c_dev->d_serial); 769 } 770 771 uint8_t 772 auclnt_get_gain(audio_stream_t *sp) 773 { 774 return (sp->s_gain_pct); 775 } 776 777 void 778 auclnt_set_muted(audio_stream_t *sp, boolean_t muted) 779 { 780 mutex_enter(&sp->s_lock); 781 782 /* if no work change, don't bother doing updates */ 783 if (sp->s_muted == muted) { 784 mutex_exit(&sp->s_lock); 785 return; 786 } 787 788 sp->s_muted = muted; 789 if (muted) { 790 sp->s_gain_eff = 0; 791 } else { 792 sp->s_gain_eff = sp->s_gain_scaled; 793 } 794 mutex_exit(&sp->s_lock); 795 796 atomic_inc_uint(&sp->s_client->c_dev->d_serial); 797 } 798 799 boolean_t 800 auclnt_get_muted(audio_stream_t *sp) 801 { 802 return (sp->s_muted); 803 } 804 805 boolean_t 806 auclnt_is_running(audio_stream_t *sp) 807 { 808 return (sp->s_running); 809 } 810 811 void 812 auclnt_start(audio_stream_t *sp) 813 { 814 mutex_enter(&sp->s_lock); 815 sp->s_running = B_TRUE; 816 mutex_exit(&sp->s_lock); 817 } 818 819 void 820 auclnt_stop(audio_stream_t *sp) 821 { 822 mutex_enter(&sp->s_lock); 823 /* if running, then stop it */ 824 if (sp->s_running) { 825 sp->s_running = B_FALSE; 826 /* 827 * if we stopped the engine, we might need to wake up 828 * a thread that is waiting for drain to complete. 829 */ 830 cv_broadcast(&sp->s_cv); 831 } 832 mutex_exit(&sp->s_lock); 833 } 834 835 /* 836 * When pausing, no new data will be played after the most recently 837 * mixed samples have played. However, the audio engine will continue 838 * to play (possibly just silence). 839 * 840 * Note that we don't reference count the device, or release/close the 841 * engine here. Once fired up, the engine continues running unil it 842 * is closed. 843 */ 844 void 845 auclnt_set_paused(audio_stream_t *sp) 846 { 847 mutex_enter(&sp->s_lock); 848 if (sp->s_paused) { 849 mutex_exit(&sp->s_lock); 850 return; 851 } 852 sp->s_paused = B_TRUE; 853 mutex_exit(&sp->s_lock); 854 855 auclnt_stop(sp); 856 857 atomic_inc_uint(&sp->s_client->c_dev->d_serial); 858 } 859 860 void 861 auclnt_clear_paused(audio_stream_t *sp) 862 { 863 mutex_enter(&sp->s_lock); 864 if (!sp->s_paused) { 865 mutex_exit(&sp->s_lock); 866 return; 867 } 868 sp->s_paused = B_FALSE; 869 mutex_exit(&sp->s_lock); 870 } 871 872 boolean_t 873 auclnt_is_paused(audio_stream_t *sp) 874 { 875 return (sp->s_paused); 876 } 877 878 void 879 auclnt_flush(audio_stream_t *sp) 880 { 881 mutex_enter(&sp->s_lock); 882 if (sp == &sp->s_client->c_ostream) { 883 sp->s_tail = sp->s_head; 884 sp->s_tidx = sp->s_hidx; 885 } else { 886 sp->s_head = sp->s_tail; 887 sp->s_hidx = sp->s_tidx; 888 } 889 sp->s_cnv_cnt = 0; 890 mutex_exit(&sp->s_lock); 891 } 892 893 int 894 auclnt_get_oflag(audio_client_t *c) 895 { 896 return (c->c_omode); 897 } 898 899 /* 900 * These routines should not be accessed by client "personality" 901 * implementations, but are for private framework use only. 902 */ 903 904 void 905 auimpl_client_init(void) 906 { 907 rw_init(&auimpl_client_lock, NULL, RW_DRIVER, NULL); 908 list_create(&auimpl_clients, sizeof (struct audio_client), 909 offsetof(struct audio_client, c_global_linkage)); 910 } 911 912 void 913 auimpl_client_fini(void) 914 { 915 rw_destroy(&auimpl_client_lock); 916 list_destroy(&auimpl_clients); 917 } 918 919 static int 920 auimpl_stream_init(audio_stream_t *sp, audio_client_t *c) 921 { 922 mutex_init(&sp->s_lock, NULL, MUTEX_DRIVER, NULL); 923 cv_init(&sp->s_cv, NULL, CV_DRIVER, NULL); 924 sp->s_client = c; 925 926 if (sp == &c->c_ostream) { 927 sp->s_user_parms = &sp->s_cnv_src_parms; 928 sp->s_phys_parms = &sp->s_cnv_dst_parms; 929 sp->s_engcap = ENGINE_OUTPUT_CAP; 930 } else { 931 ASSERT(sp == &c->c_istream); 932 sp->s_user_parms = &sp->s_cnv_dst_parms; 933 sp->s_phys_parms = &sp->s_cnv_src_parms; 934 sp->s_engcap = ENGINE_INPUT_CAP; 935 } 936 937 /* for now initialize conversion parameters */ 938 sp->s_src_quality = 3; /* reasonable compromise for now */ 939 sp->s_cnv_dst_nchan = 2; 940 sp->s_cnv_dst_format = AUDIO_FORMAT_S24_NE; 941 sp->s_cnv_dst_rate = 48000; 942 sp->s_cnv_src_nchan = 2; 943 sp->s_cnv_src_format = AUDIO_FORMAT_S24_NE; 944 sp->s_cnv_src_rate = 48000; 945 946 /* set volume/gain all the way up */ 947 sp->s_muted = B_FALSE; 948 sp->s_gain_pct = 0; 949 sp->s_gain_scaled = AUDIO_VOL_SCALE; 950 sp->s_gain_eff = AUDIO_VOL_SCALE; 951 952 /* 953 * We have to start off with a reasonable buffer and 954 * interrupt configuration. 955 */ 956 sp->s_allocsz = 65536; 957 sp->s_data = ddi_umem_alloc(sp->s_allocsz, DDI_UMEM_NOSLEEP, 958 &sp->s_cookie); 959 if (sp->s_data == NULL) { 960 sp->s_allocsz = 0; 961 audio_dev_warn(c->c_dev, "ddi_umem_alloc failed"); 962 return (ENOMEM); 963 } 964 /* make sure no stale data left in stream */ 965 bzero(sp->s_data, sp->s_allocsz); 966 967 /* 968 * Allocate SRC and data conversion state. 969 */ 970 mutex_enter(&sp->s_lock); 971 if (auimpl_format_alloc(sp) != 0) { 972 mutex_exit(&sp->s_lock); 973 return (ENOMEM); 974 } 975 976 mutex_exit(&sp->s_lock); 977 978 return (0); 979 } 980 981 982 static void 983 audio_stream_fini(audio_stream_t *sp) 984 { 985 auimpl_format_free(sp); 986 if (sp->s_cnv_buf0) 987 kmem_free(sp->s_cnv_buf0, sp->s_cnv_max); 988 if (sp->s_cnv_buf1) 989 kmem_free(sp->s_cnv_buf1, sp->s_cnv_max); 990 mutex_destroy(&sp->s_lock); 991 cv_destroy(&sp->s_cv); 992 if (sp->s_data != NULL) { 993 ddi_umem_free(sp->s_cookie); 994 sp->s_data = NULL; 995 } 996 } 997 998 int 999 auclnt_start_drain(audio_client_t *c) 1000 { 1001 audio_stream_t *sp; 1002 int rv; 1003 1004 sp = &c->c_ostream; 1005 1006 /* start an asynchronous drain operation. */ 1007 mutex_enter(&sp->s_lock); 1008 if (sp->s_paused || !sp->s_running) { 1009 rv = EALREADY; 1010 } else { 1011 sp->s_draining = B_TRUE; 1012 rv = 0; 1013 } 1014 mutex_exit(&sp->s_lock); 1015 return (rv); 1016 } 1017 1018 int 1019 auclnt_drain(audio_client_t *c) 1020 { 1021 audio_stream_t *sp; 1022 1023 sp = &c->c_ostream; 1024 1025 /* 1026 * Note: Drain logic will automatically "stop" the stream when 1027 * the drain threshold has been reached. So all we have to do 1028 * is wait for the stream to stop. 1029 */ 1030 mutex_enter(&sp->s_lock); 1031 sp->s_draining = B_TRUE; 1032 while (sp->s_draining && sp->s_running && !sp->s_paused) { 1033 if (cv_wait_sig(&sp->s_cv, &sp->s_lock) == 0) { 1034 mutex_exit(&sp->s_lock); 1035 return (EINTR); 1036 } 1037 } 1038 mutex_exit(&sp->s_lock); 1039 return (0); 1040 } 1041 1042 audio_client_t * 1043 auimpl_client_create(dev_t dev) 1044 { 1045 audio_client_ops_t *ops; 1046 audio_client_t *c; 1047 audio_client_t *next; 1048 list_t *list = &auimpl_clients; 1049 minor_t minor; 1050 audio_dev_t *d; 1051 1052 /* validate minor number */ 1053 minor = getminor(dev) & AUDIO_MN_TYPE_MASK; 1054 if ((ops = audio_client_ops[minor]) == NULL) { 1055 return (NULL); 1056 } 1057 1058 /* lookup device instance */ 1059 if ((d = auimpl_dev_hold_by_devt(dev)) == NULL) { 1060 audio_dev_warn(NULL, "no audio_dev for dev_t %d,%d", 1061 getmajor(dev), getminor(dev)); 1062 return (NULL); 1063 } 1064 1065 if ((c = kmem_zalloc(sizeof (*c), KM_NOSLEEP)) == NULL) { 1066 audio_dev_warn(d, "unable to allocate client structure"); 1067 auimpl_dev_release(d); 1068 return (NULL); 1069 } 1070 c->c_dev = d; 1071 1072 mutex_init(&c->c_lock, NULL, MUTEX_DRIVER, NULL); 1073 cv_init(&c->c_cv, NULL, CV_DRIVER, NULL); 1074 1075 if ((auimpl_stream_init(&c->c_ostream, c) != 0) || 1076 (auimpl_stream_init(&c->c_istream, c) != 0)) { 1077 goto failed; 1078 } 1079 1080 c->c_major = getmajor(dev); 1081 c->c_origminor = getminor(dev); 1082 c->c_ops = *ops; 1083 1084 /* 1085 * We hold the client lock here. 1086 */ 1087 rw_enter(&auimpl_client_lock, RW_WRITER); 1088 1089 minor = AUDIO_MN_CLONE_MASK; 1090 for (next = list_head(list); next; next = list_next(list, next)) { 1091 if (next->c_minor > minor) { 1092 break; 1093 } 1094 minor++; 1095 } 1096 if (minor >= MAXMIN32) { 1097 rw_exit(&auimpl_client_lock); 1098 goto failed; 1099 } 1100 c->c_minor = minor; 1101 list_insert_before(list, next, c); 1102 1103 rw_exit(&auimpl_client_lock); 1104 1105 1106 return (c); 1107 1108 failed: 1109 auimpl_dev_release(d); 1110 audio_stream_fini(&c->c_ostream); 1111 audio_stream_fini(&c->c_istream); 1112 mutex_destroy(&c->c_lock); 1113 cv_destroy(&c->c_cv); 1114 kmem_free(c, sizeof (*c)); 1115 return (NULL); 1116 } 1117 1118 void 1119 auimpl_client_destroy(audio_client_t *c) 1120 { 1121 /* remove us from the global list */ 1122 rw_enter(&auimpl_client_lock, RW_WRITER); 1123 list_remove(&auimpl_clients, c); 1124 rw_exit(&auimpl_client_lock); 1125 1126 ASSERT(!c->c_istream.s_running); 1127 ASSERT(!c->c_istream.s_running); 1128 1129 /* release the device reference count */ 1130 auimpl_dev_release(c->c_dev); 1131 c->c_dev = NULL; 1132 1133 mutex_destroy(&c->c_lock); 1134 cv_destroy(&c->c_cv); 1135 1136 audio_stream_fini(&c->c_istream); 1137 audio_stream_fini(&c->c_ostream); 1138 kmem_free(c, sizeof (*c)); 1139 } 1140 1141 void 1142 auimpl_client_activate(audio_client_t *c) 1143 { 1144 rw_enter(&auimpl_client_lock, RW_WRITER); 1145 c->c_is_active = B_TRUE; 1146 rw_exit(&auimpl_client_lock); 1147 } 1148 1149 void 1150 auimpl_client_deactivate(audio_client_t *c) 1151 { 1152 rw_enter(&auimpl_client_lock, RW_WRITER); 1153 c->c_is_active = B_FALSE; 1154 rw_exit(&auimpl_client_lock); 1155 } 1156 1157 void 1158 auclnt_close(audio_client_t *c) 1159 { 1160 audio_dev_t *d = c->c_dev; 1161 1162 /* stop the engines if they are running */ 1163 auclnt_stop(&c->c_istream); 1164 auclnt_stop(&c->c_ostream); 1165 1166 rw_enter(&auimpl_client_lock, RW_WRITER); 1167 list_remove(&d->d_clients, c); 1168 rw_exit(&auimpl_client_lock); 1169 1170 mutex_enter(&c->c_lock); 1171 /* if in transition need to wait for other thread to release */ 1172 while (c->c_refcnt) { 1173 cv_wait(&c->c_cv, &c->c_lock); 1174 } 1175 mutex_exit(&c->c_lock); 1176 1177 /* release any engines that we were holding */ 1178 auimpl_engine_close(&c->c_ostream); 1179 auimpl_engine_close(&c->c_istream); 1180 } 1181 1182 audio_dev_t * 1183 auclnt_hold_dev_by_index(int index) 1184 { 1185 return (auimpl_dev_hold_by_index(index)); 1186 } 1187 1188 void 1189 auclnt_release_dev(audio_dev_t *dev) 1190 { 1191 auimpl_dev_release(dev); 1192 } 1193 1194 audio_client_t * 1195 auclnt_hold_by_devt(dev_t dev) 1196 { 1197 minor_t mn = getminor(dev); 1198 major_t mj = getmajor(dev); 1199 list_t *list; 1200 audio_client_t *c; 1201 1202 list = &auimpl_clients; 1203 /* linked list search is kind of inefficient, but it works */ 1204 rw_enter(&auimpl_client_lock, RW_READER); 1205 for (c = list_head(list); c != NULL; c = list_next(list, c)) { 1206 if ((c->c_major == mj) && (c->c_minor == mn)) { 1207 mutex_enter(&c->c_lock); 1208 if (c->c_is_active) { 1209 c->c_refcnt++; 1210 mutex_exit(&c->c_lock); 1211 } else { 1212 mutex_exit(&c->c_lock); 1213 c = NULL; 1214 } 1215 break; 1216 } 1217 } 1218 rw_exit(&auimpl_client_lock); 1219 return (c); 1220 } 1221 1222 int 1223 auclnt_serialize(audio_client_t *c) 1224 { 1225 mutex_enter(&c->c_lock); 1226 while (c->c_serialize) { 1227 if (cv_wait_sig(&c->c_cv, &c->c_lock) == 0) { 1228 mutex_exit(&c->c_lock); 1229 return (EINTR); 1230 } 1231 } 1232 c->c_serialize = B_TRUE; 1233 mutex_exit(&c->c_lock); 1234 return (0); 1235 } 1236 1237 void 1238 auclnt_unserialize(audio_client_t *c) 1239 { 1240 mutex_enter(&c->c_lock); 1241 ASSERT(c->c_serialize); 1242 c->c_serialize = B_FALSE; 1243 cv_broadcast(&c->c_cv); 1244 mutex_exit(&c->c_lock); 1245 } 1246 1247 void 1248 auclnt_hold(audio_client_t *c) 1249 { 1250 mutex_enter(&c->c_lock); 1251 c->c_refcnt++; 1252 mutex_exit(&c->c_lock); 1253 } 1254 1255 void 1256 auclnt_release(audio_client_t *c) 1257 { 1258 mutex_enter(&c->c_lock); 1259 ASSERT(c->c_refcnt > 0); 1260 c->c_refcnt--; 1261 if (c->c_refcnt == 0) 1262 cv_broadcast(&c->c_cv); 1263 mutex_exit(&c->c_lock); 1264 } 1265 1266 uint_t 1267 auclnt_dev_get_serial(audio_dev_t *d) 1268 { 1269 return (d->d_serial); 1270 } 1271 1272 void 1273 auclnt_dev_walk_clients(audio_dev_t *d, 1274 int (*walker)(audio_client_t *, void *), 1275 void *arg) 1276 { 1277 list_t *l = &d->d_clients; 1278 audio_client_t *c; 1279 int rv; 1280 1281 rw_enter(&auimpl_client_lock, RW_READER); 1282 restart: 1283 for (c = list_head(l); c != NULL; c = list_next(l, c)) { 1284 if (!c->c_is_active) 1285 continue; 1286 rv = (walker(c, arg)); 1287 if (rv == AUDIO_WALK_STOP) { 1288 break; 1289 } else if (rv == AUDIO_WALK_RESTART) { 1290 goto restart; 1291 } 1292 } 1293 rw_exit(&auimpl_client_lock); 1294 } 1295 1296 1297 int 1298 auclnt_open(audio_client_t *c, uint_t fmts, int oflag) 1299 { 1300 audio_stream_t *sp; 1301 audio_dev_t *d = c->c_dev; 1302 int rv = 0; 1303 int flags; 1304 audio_parms_t parms; 1305 1306 flags = 0; 1307 if (oflag & FNDELAY) 1308 flags |= ENGINE_NDELAY; 1309 1310 if (oflag & FWRITE) { 1311 sp = &c->c_ostream; 1312 rv = auimpl_engine_open(d, fmts, flags | ENGINE_OUTPUT, sp); 1313 1314 if (rv != 0) { 1315 goto done; 1316 } 1317 mutex_enter(&sp->s_lock); 1318 parms = *sp->s_user_parms; 1319 rv = auimpl_format_setup(sp, &parms); 1320 mutex_exit(&sp->s_lock); 1321 if (rv != 0) { 1322 goto done; 1323 } 1324 } 1325 1326 if (oflag & FREAD) { 1327 sp = &c->c_istream; 1328 rv = auimpl_engine_open(d, fmts, flags | ENGINE_INPUT, sp); 1329 1330 if (rv != 0) { 1331 goto done; 1332 } 1333 mutex_enter(&sp->s_lock); 1334 parms = *sp->s_user_parms; 1335 rv = auimpl_format_setup(sp, &parms); 1336 mutex_exit(&sp->s_lock); 1337 if (rv != 0) { 1338 goto done; 1339 } 1340 } 1341 1342 done: 1343 if (rv != 0) { 1344 /* close any engines that we opened */ 1345 auimpl_engine_close(&c->c_ostream); 1346 auimpl_engine_close(&c->c_istream); 1347 } else { 1348 rw_enter(&auimpl_client_lock, RW_WRITER); 1349 list_insert_tail(&d->d_clients, c); 1350 c->c_ostream.s_gain_master = d->d_pcmvol; 1351 c->c_istream.s_gain_master = 100; 1352 rw_exit(&auimpl_client_lock); 1353 auclnt_set_gain(&c->c_ostream, 100); 1354 auclnt_set_gain(&c->c_istream, 100); 1355 } 1356 1357 return (rv); 1358 } 1359 1360 minor_t 1361 auclnt_get_minor(audio_client_t *c) 1362 { 1363 return (c->c_minor); 1364 } 1365 1366 minor_t 1367 auclnt_get_original_minor(audio_client_t *c) 1368 { 1369 return (c->c_origminor); 1370 } 1371 1372 minor_t 1373 auclnt_get_minor_type(audio_client_t *c) 1374 { 1375 return (c->c_origminor & AUDIO_MN_TYPE_MASK); 1376 } 1377 1378 queue_t * 1379 auclnt_get_rq(audio_client_t *c) 1380 { 1381 return (c->c_rq); 1382 } 1383 1384 queue_t * 1385 auclnt_get_wq(audio_client_t *c) 1386 { 1387 return (c->c_wq); 1388 } 1389 1390 pid_t 1391 auclnt_get_pid(audio_client_t *c) 1392 { 1393 return (c->c_pid); 1394 } 1395 1396 cred_t * 1397 auclnt_get_cred(audio_client_t *c) 1398 { 1399 return (c->c_cred); 1400 } 1401 1402 audio_dev_t * 1403 auclnt_get_dev(audio_client_t *c) 1404 { 1405 return (c->c_dev); 1406 } 1407 1408 int 1409 auclnt_get_dev_number(audio_dev_t *dev) 1410 { 1411 return (dev->d_number); 1412 } 1413 1414 int 1415 auclnt_get_dev_index(audio_dev_t *dev) 1416 { 1417 return (dev->d_index); 1418 } 1419 1420 const char * 1421 auclnt_get_dev_name(audio_dev_t *dev) 1422 { 1423 return (dev->d_name); 1424 } 1425 1426 const char * 1427 auclnt_get_dev_driver(audio_dev_t *dev) 1428 { 1429 return (ddi_driver_name(dev->d_dip)); 1430 } 1431 1432 dev_info_t * 1433 auclnt_get_dev_devinfo(audio_dev_t *dev) 1434 { 1435 return (dev->d_dip); 1436 } 1437 1438 const char * 1439 auclnt_get_dev_hw_info(audio_dev_t *dev, void **iter) 1440 { 1441 struct audio_infostr *isp = *iter; 1442 if (isp == NULL) { 1443 isp = list_head(&dev->d_hwinfo); 1444 } else { 1445 isp = list_next(&dev->d_hwinfo, isp); 1446 } 1447 1448 *iter = isp; 1449 return (isp ? isp->i_line : NULL); 1450 } 1451 1452 int 1453 auclnt_get_dev_instance(audio_dev_t *dev) 1454 { 1455 return (dev->d_instance); 1456 } 1457 1458 const char * 1459 auclnt_get_dev_description(audio_dev_t *dev) 1460 { 1461 return (dev->d_desc); 1462 } 1463 1464 const char * 1465 auclnt_get_dev_version(audio_dev_t *dev) 1466 { 1467 return (dev->d_vers); 1468 } 1469 1470 uint_t 1471 auclnt_get_dev_capab(audio_dev_t *dev) 1472 { 1473 uint32_t flags; 1474 uint_t caps = 0; 1475 1476 flags = dev->d_flags; 1477 1478 if (flags & DEV_OUTPUT_CAP) 1479 caps |= AUDIO_CLIENT_CAP_PLAY; 1480 if (flags & DEV_INPUT_CAP) 1481 caps |= AUDIO_CLIENT_CAP_RECORD; 1482 if (flags & DEV_DUPLEX_CAP) 1483 caps |= AUDIO_CLIENT_CAP_DUPLEX; 1484 1485 /* AC3: deal with formats that don't support mixing */ 1486 1487 return (caps); 1488 } 1489 1490 uint64_t 1491 auclnt_get_samples(audio_stream_t *sp) 1492 { 1493 uint64_t n; 1494 1495 mutex_enter(&sp->s_lock); 1496 n = sp->s_samples; 1497 mutex_exit(&sp->s_lock); 1498 return (n); 1499 } 1500 1501 void 1502 auclnt_set_samples(audio_stream_t *sp, uint64_t n) 1503 { 1504 mutex_enter(&sp->s_lock); 1505 sp->s_samples = n; 1506 mutex_exit(&sp->s_lock); 1507 } 1508 1509 uint64_t 1510 auclnt_get_errors(audio_stream_t *sp) 1511 { 1512 uint64_t n; 1513 mutex_enter(&sp->s_lock); 1514 n = sp->s_errors; 1515 mutex_exit(&sp->s_lock); 1516 return (n); 1517 } 1518 1519 void 1520 auclnt_set_errors(audio_stream_t *sp, uint64_t n) 1521 { 1522 mutex_enter(&sp->s_lock); 1523 sp->s_errors = n; 1524 mutex_exit(&sp->s_lock); 1525 } 1526 1527 void 1528 auclnt_register_ops(minor_t minor, audio_client_ops_t *ops) 1529 { 1530 /* we control minor number allocations, no need for runtime checks */ 1531 ASSERT(minor <= AUDIO_MN_TYPE_MASK); 1532 1533 audio_client_ops[minor] = ops; 1534 } 1535 1536 int 1537 auimpl_create_minors(audio_dev_t *d) 1538 { 1539 char path[MAXPATHLEN]; 1540 int rv = 0; 1541 minor_t minor; 1542 audio_client_ops_t *ops; 1543 char *nt; 1544 1545 for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) { 1546 1547 if ((ops = audio_client_ops[i]) == NULL) 1548 continue; 1549 1550 if (ops->aco_dev_init != NULL) 1551 d->d_minor_data[i] = ops->aco_dev_init(d); 1552 1553 switch (i) { 1554 case AUDIO_MINOR_SNDSTAT: 1555 if (!(d->d_flags & DEV_SNDSTAT_CAP)) { 1556 continue; 1557 } 1558 nt = DDI_PSEUDO; 1559 break; 1560 1561 default: 1562 if (!(d->d_flags & (DEV_INPUT_CAP| DEV_OUTPUT_CAP))) { 1563 continue; 1564 } 1565 nt = DDI_NT_AUDIO; 1566 break; 1567 } 1568 1569 if (ops->aco_minor_prefix != NULL) { 1570 1571 minor = AUDIO_MKMN(d->d_instance, i); 1572 (void) snprintf(path, sizeof (path), 1573 "%s%d", ops->aco_minor_prefix, d->d_instance); 1574 1575 rv = ddi_create_minor_node(d->d_dip, path, S_IFCHR, 1576 minor, nt, 0); 1577 1578 if (rv != 0) 1579 break; 1580 } 1581 } 1582 return (rv); 1583 } 1584 1585 void 1586 auimpl_remove_minors(audio_dev_t *d) 1587 { 1588 char path[MAXPATHLEN]; 1589 audio_client_ops_t *ops; 1590 1591 for (int i = 0; i <= AUDIO_MN_TYPE_MASK; i++) { 1592 if ((ops = audio_client_ops[i]) == NULL) 1593 continue; 1594 if (ops->aco_minor_prefix != NULL) { 1595 (void) snprintf(path, sizeof (path), "%s%d", 1596 ops->aco_minor_prefix, d->d_instance); 1597 (void) ddi_remove_minor_node(d->d_dip, path); 1598 } 1599 1600 if (ops->aco_dev_fini != NULL) 1601 ops->aco_dev_fini(d->d_minor_data[i]); 1602 } 1603 } 1604 1605 void * 1606 auclnt_get_dev_minor_data(audio_dev_t *d, minor_t mn) 1607 { 1608 ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS)); 1609 return (d->d_minor_data[mn]); 1610 } 1611 1612 void * 1613 auclnt_get_minor_data(audio_client_t *c, minor_t mn) 1614 { 1615 ASSERT(mn < (1U << AUDIO_MN_TYPE_NBITS)); 1616 return (c->c_dev->d_minor_data[mn]); 1617 } 1618 1619 /* 1620 * This will walk all controls registered to a clients device and callback 1621 * to walker for each one with its audio_ctrl. Note this data 1622 * must be considered read only by walker. 1623 * 1624 * Note that walk_func may return values to continue (AUDIO_WALK_CONTINUE) 1625 * or stop walk (AUDIO_WALK_STOP). 1626 * 1627 */ 1628 void 1629 auclnt_walk_controls(audio_dev_t *d, 1630 int (*walker)(audio_ctrl_t *, void *), 1631 void *arg) 1632 { 1633 audio_ctrl_t *ctrl; 1634 1635 mutex_enter(&d->d_ctrl_lock); 1636 for (ctrl = list_head(&d->d_controls); ctrl; 1637 ctrl = list_next(&d->d_controls, ctrl)) { 1638 if (walker(ctrl, arg) == AUDIO_WALK_STOP) 1639 break; 1640 } 1641 mutex_exit(&d->d_ctrl_lock); 1642 } 1643 1644 /* 1645 * This will search all controls attached to an 1646 * audio device for a control with the desired name. 1647 * 1648 * d - the audio device to look on 1649 * name - name of the control being looked for. 1650 * 1651 * On successful return a ctrl handle will be returned. On 1652 * failure NULL is returned. 1653 */ 1654 audio_ctrl_t * 1655 auclnt_find_control(audio_dev_t *d, const char *name) 1656 { 1657 audio_ctrl_t *ctrl; 1658 1659 /* Verify argument */ 1660 ASSERT(d); 1661 1662 mutex_enter(&d->d_ctrl_lock); 1663 for (ctrl = list_head(&d->d_controls); ctrl; 1664 ctrl = list_next(&d->d_controls, ctrl)) { 1665 if (strcmp(ctrl->ctrl_name, name) == 0) { 1666 mutex_exit(&d->d_ctrl_lock); 1667 return (ctrl); 1668 } 1669 } 1670 mutex_exit(&d->d_ctrl_lock); 1671 return (NULL); 1672 } 1673 1674 /* 1675 * Given a known control, get its attributes. 1676 * 1677 * The caller must supply a audio_ctrl_desc_t structure. Also the 1678 * values in the structure are ignored when making the call and filled 1679 * in by this function. All data pointed to by elements of desc should 1680 * be assumed read only. 1681 * 1682 * If an error occurs then a non-zero is returned. 1683 * 1684 */ 1685 int 1686 auclnt_control_describe(audio_ctrl_t *ctrl, audio_ctrl_desc_t *desc) 1687 { 1688 ASSERT(ctrl); 1689 ASSERT(desc); 1690 1691 bcopy(&ctrl->ctrl_des, desc, sizeof (*desc)); 1692 return (0); 1693 } 1694 1695 int 1696 auclnt_control_read(audio_ctrl_t *ctrl, uint64_t *value) 1697 { 1698 return (audio_control_read(ctrl, value)); 1699 } 1700 1701 int 1702 auclnt_control_write(audio_ctrl_t *ctrl, uint64_t value) 1703 { 1704 return (audio_control_write(ctrl, value)); 1705 } 1706 1707 void 1708 auclnt_warn(audio_client_t *c, const char *fmt, ...) 1709 { 1710 va_list va; 1711 1712 va_start(va, fmt); 1713 auimpl_dev_vwarn(c ? c->c_dev : NULL, fmt, va); 1714 va_end(va); 1715 } 1716