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