1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org> 5 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006 6 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org> 7 * Portions Copyright (c) Luigi Rizzo <luigi@FreeBSD.org> - 1997-99 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifdef HAVE_KERNEL_OPTION_HEADERS 33 #include "opt_snd.h" 34 #endif 35 36 #include <dev/sound/pcm/sound.h> 37 #include <dev/sound/pcm/vchan.h> 38 39 #include "feeder_if.h" 40 41 int report_soft_formats = 1; 42 SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW, 43 &report_soft_formats, 0, "report software-emulated formats"); 44 45 int report_soft_matrix = 1; 46 SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_matrix, CTLFLAG_RW, 47 &report_soft_matrix, 0, "report software-emulated channel matrixing"); 48 49 int chn_latency = CHN_LATENCY_DEFAULT; 50 51 static int 52 sysctl_hw_snd_latency(SYSCTL_HANDLER_ARGS) 53 { 54 int err, val; 55 56 val = chn_latency; 57 err = sysctl_handle_int(oidp, &val, 0, req); 58 if (err != 0 || req->newptr == NULL) 59 return err; 60 if (val < CHN_LATENCY_MIN || val > CHN_LATENCY_MAX) 61 err = EINVAL; 62 else 63 chn_latency = val; 64 65 return err; 66 } 67 SYSCTL_PROC(_hw_snd, OID_AUTO, latency, 68 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int), 69 sysctl_hw_snd_latency, "I", 70 "buffering latency (0=low ... 10=high)"); 71 72 int chn_latency_profile = CHN_LATENCY_PROFILE_DEFAULT; 73 74 static int 75 sysctl_hw_snd_latency_profile(SYSCTL_HANDLER_ARGS) 76 { 77 int err, val; 78 79 val = chn_latency_profile; 80 err = sysctl_handle_int(oidp, &val, 0, req); 81 if (err != 0 || req->newptr == NULL) 82 return err; 83 if (val < CHN_LATENCY_PROFILE_MIN || val > CHN_LATENCY_PROFILE_MAX) 84 err = EINVAL; 85 else 86 chn_latency_profile = val; 87 88 return err; 89 } 90 SYSCTL_PROC(_hw_snd, OID_AUTO, latency_profile, 91 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int), 92 sysctl_hw_snd_latency_profile, "I", 93 "buffering latency profile (0=aggressive 1=safe)"); 94 95 static int chn_timeout = CHN_TIMEOUT; 96 97 static int 98 sysctl_hw_snd_timeout(SYSCTL_HANDLER_ARGS) 99 { 100 int err, val; 101 102 val = chn_timeout; 103 err = sysctl_handle_int(oidp, &val, 0, req); 104 if (err != 0 || req->newptr == NULL) 105 return err; 106 if (val < CHN_TIMEOUT_MIN || val > CHN_TIMEOUT_MAX) 107 err = EINVAL; 108 else 109 chn_timeout = val; 110 111 return err; 112 } 113 SYSCTL_PROC(_hw_snd, OID_AUTO, timeout, 114 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, sizeof(int), 115 sysctl_hw_snd_timeout, "I", 116 "interrupt timeout (1 - 10) seconds"); 117 118 static int chn_vpc_autoreset = 1; 119 SYSCTL_INT(_hw_snd, OID_AUTO, vpc_autoreset, CTLFLAG_RWTUN, 120 &chn_vpc_autoreset, 0, "automatically reset channels volume to 0db"); 121 122 static int chn_vol_0db_pcm = SND_VOL_0DB_PCM; 123 124 static void 125 chn_vpc_proc(int reset, int db) 126 { 127 struct snddev_info *d; 128 struct pcm_channel *c; 129 int i; 130 131 for (i = 0; pcm_devclass != NULL && 132 i < devclass_get_maxunit(pcm_devclass); i++) { 133 d = devclass_get_softc(pcm_devclass, i); 134 if (!PCM_REGISTERED(d)) 135 continue; 136 PCM_LOCK(d); 137 PCM_WAIT(d); 138 PCM_ACQUIRE(d); 139 CHN_FOREACH(c, d, channels.pcm) { 140 CHN_LOCK(c); 141 CHN_SETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_VOL_0DB, db); 142 if (reset != 0) 143 chn_vpc_reset(c, SND_VOL_C_PCM, 1); 144 CHN_UNLOCK(c); 145 } 146 PCM_RELEASE(d); 147 PCM_UNLOCK(d); 148 } 149 } 150 151 static int 152 sysctl_hw_snd_vpc_0db(SYSCTL_HANDLER_ARGS) 153 { 154 int err, val; 155 156 val = chn_vol_0db_pcm; 157 err = sysctl_handle_int(oidp, &val, 0, req); 158 if (err != 0 || req->newptr == NULL) 159 return (err); 160 if (val < SND_VOL_0DB_MIN || val > SND_VOL_0DB_MAX) 161 return (EINVAL); 162 163 chn_vol_0db_pcm = val; 164 chn_vpc_proc(0, val); 165 166 return (0); 167 } 168 SYSCTL_PROC(_hw_snd, OID_AUTO, vpc_0db, 169 CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), 170 sysctl_hw_snd_vpc_0db, "I", 171 "0db relative level"); 172 173 static int 174 sysctl_hw_snd_vpc_reset(SYSCTL_HANDLER_ARGS) 175 { 176 int err, val; 177 178 val = 0; 179 err = sysctl_handle_int(oidp, &val, 0, req); 180 if (err != 0 || req->newptr == NULL || val == 0) 181 return (err); 182 183 chn_vol_0db_pcm = SND_VOL_0DB_PCM; 184 chn_vpc_proc(1, SND_VOL_0DB_PCM); 185 186 return (0); 187 } 188 SYSCTL_PROC(_hw_snd, OID_AUTO, vpc_reset, 189 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 0, sizeof(int), 190 sysctl_hw_snd_vpc_reset, "I", 191 "reset volume on all channels"); 192 193 static int chn_usefrags = 0; 194 static int chn_syncdelay = -1; 195 196 SYSCTL_INT(_hw_snd, OID_AUTO, usefrags, CTLFLAG_RWTUN, 197 &chn_usefrags, 0, "prefer setfragments() over setblocksize()"); 198 SYSCTL_INT(_hw_snd, OID_AUTO, syncdelay, CTLFLAG_RWTUN, 199 &chn_syncdelay, 0, 200 "append (0-1000) millisecond trailing buffer delay on each sync"); 201 202 /** 203 * @brief Channel sync group lock 204 * 205 * Clients should acquire this lock @b without holding any channel locks 206 * before touching syncgroups or the main syncgroup list. 207 */ 208 struct mtx snd_pcm_syncgroups_mtx; 209 MTX_SYSINIT(pcm_syncgroup, &snd_pcm_syncgroups_mtx, "PCM channel sync group lock", MTX_DEF); 210 /** 211 * @brief syncgroups' master list 212 * 213 * Each time a channel syncgroup is created, it's added to this list. This 214 * list should only be accessed with @sa snd_pcm_syncgroups_mtx held. 215 * 216 * See SNDCTL_DSP_SYNCGROUP for more information. 217 */ 218 struct pcm_synclist snd_pcm_syncgroups = SLIST_HEAD_INITIALIZER(snd_pcm_syncgroups); 219 220 static void 221 chn_lockinit(struct pcm_channel *c, int dir) 222 { 223 switch (dir) { 224 case PCMDIR_PLAY: 225 c->lock = snd_mtxcreate(c->name, "pcm play channel"); 226 cv_init(&c->intr_cv, "pcmwr"); 227 break; 228 case PCMDIR_PLAY_VIRTUAL: 229 c->lock = snd_mtxcreate(c->name, "pcm virtual play channel"); 230 cv_init(&c->intr_cv, "pcmwrv"); 231 break; 232 case PCMDIR_REC: 233 c->lock = snd_mtxcreate(c->name, "pcm record channel"); 234 cv_init(&c->intr_cv, "pcmrd"); 235 break; 236 case PCMDIR_REC_VIRTUAL: 237 c->lock = snd_mtxcreate(c->name, "pcm virtual record channel"); 238 cv_init(&c->intr_cv, "pcmrdv"); 239 break; 240 default: 241 panic("%s(): Invalid direction=%d", __func__, dir); 242 break; 243 } 244 245 cv_init(&c->cv, "pcmchn"); 246 } 247 248 static void 249 chn_lockdestroy(struct pcm_channel *c) 250 { 251 CHN_LOCKASSERT(c); 252 253 CHN_BROADCAST(&c->cv); 254 CHN_BROADCAST(&c->intr_cv); 255 256 cv_destroy(&c->cv); 257 cv_destroy(&c->intr_cv); 258 259 snd_mtxfree(c->lock); 260 } 261 262 /** 263 * @brief Determine channel is ready for I/O 264 * 265 * @retval 1 = ready for I/O 266 * @retval 0 = not ready for I/O 267 */ 268 static int 269 chn_polltrigger(struct pcm_channel *c) 270 { 271 struct snd_dbuf *bs = c->bufsoft; 272 u_int delta; 273 274 CHN_LOCKASSERT(c); 275 276 if (c->flags & CHN_F_MMAP) { 277 if (sndbuf_getprevtotal(bs) < c->lw) 278 delta = c->lw; 279 else 280 delta = sndbuf_gettotal(bs) - sndbuf_getprevtotal(bs); 281 } else { 282 if (c->direction == PCMDIR_PLAY) 283 delta = sndbuf_getfree(bs); 284 else 285 delta = sndbuf_getready(bs); 286 } 287 288 return ((delta < c->lw) ? 0 : 1); 289 } 290 291 static void 292 chn_pollreset(struct pcm_channel *c) 293 { 294 295 CHN_LOCKASSERT(c); 296 sndbuf_updateprevtotal(c->bufsoft); 297 } 298 299 static void 300 chn_wakeup(struct pcm_channel *c) 301 { 302 struct snd_dbuf *bs; 303 struct pcm_channel *ch; 304 305 CHN_LOCKASSERT(c); 306 307 bs = c->bufsoft; 308 309 if (CHN_EMPTY(c, children.busy)) { 310 if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c)) 311 selwakeuppri(sndbuf_getsel(bs), PRIBIO); 312 if (c->flags & CHN_F_SLEEPING) { 313 /* 314 * Ok, I can just panic it right here since it is 315 * quite obvious that we never allow multiple waiters 316 * from userland. I'm too generous... 317 */ 318 CHN_BROADCAST(&c->intr_cv); 319 } 320 } else { 321 CHN_FOREACH(ch, c, children.busy) { 322 CHN_LOCK(ch); 323 chn_wakeup(ch); 324 CHN_UNLOCK(ch); 325 } 326 } 327 } 328 329 static int 330 chn_sleep(struct pcm_channel *c, int timeout) 331 { 332 int ret; 333 334 CHN_LOCKASSERT(c); 335 336 if (c->flags & CHN_F_DEAD) 337 return (EINVAL); 338 339 c->flags |= CHN_F_SLEEPING; 340 ret = cv_timedwait_sig(&c->intr_cv, c->lock, timeout); 341 c->flags &= ~CHN_F_SLEEPING; 342 343 return ((c->flags & CHN_F_DEAD) ? EINVAL : ret); 344 } 345 346 /* 347 * chn_dmaupdate() tracks the status of a dma transfer, 348 * updating pointers. 349 */ 350 351 static unsigned int 352 chn_dmaupdate(struct pcm_channel *c) 353 { 354 struct snd_dbuf *b = c->bufhard; 355 unsigned int delta, old, hwptr, amt; 356 357 KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0")); 358 CHN_LOCKASSERT(c); 359 360 old = sndbuf_gethwptr(b); 361 hwptr = chn_getptr(c); 362 delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b); 363 sndbuf_sethwptr(b, hwptr); 364 365 if (c->direction == PCMDIR_PLAY) { 366 amt = min(delta, sndbuf_getready(b)); 367 amt -= amt % sndbuf_getalign(b); 368 if (amt > 0) 369 sndbuf_dispose(b, NULL, amt); 370 } else { 371 amt = min(delta, sndbuf_getfree(b)); 372 amt -= amt % sndbuf_getalign(b); 373 if (amt > 0) 374 sndbuf_acquire(b, NULL, amt); 375 } 376 if (snd_verbose > 3 && CHN_STARTED(c) && delta == 0) { 377 device_printf(c->dev, "WARNING: %s DMA completion " 378 "too fast/slow ! hwptr=%u, old=%u " 379 "delta=%u amt=%u ready=%u free=%u\n", 380 CHN_DIRSTR(c), hwptr, old, delta, amt, 381 sndbuf_getready(b), sndbuf_getfree(b)); 382 } 383 384 return delta; 385 } 386 387 static void 388 chn_wrfeed(struct pcm_channel *c) 389 { 390 struct snd_dbuf *b = c->bufhard; 391 struct snd_dbuf *bs = c->bufsoft; 392 unsigned int amt, want, wasfree; 393 394 CHN_LOCKASSERT(c); 395 396 if ((c->flags & CHN_F_MMAP) && !(c->flags & CHN_F_CLOSING)) 397 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs)); 398 399 wasfree = sndbuf_getfree(b); 400 want = min(sndbuf_getsize(b), 401 imax(0, sndbuf_xbytes(sndbuf_getsize(bs), bs, b) - 402 sndbuf_getready(b))); 403 amt = min(wasfree, want); 404 if (amt > 0) 405 sndbuf_feed(bs, b, c, c->feeder, amt); 406 407 /* 408 * Possible xruns. There should be no empty space left in buffer. 409 */ 410 if (sndbuf_getready(b) < want) 411 c->xruns++; 412 413 if (sndbuf_getfree(b) < wasfree) 414 chn_wakeup(c); 415 } 416 417 #if 0 418 static void 419 chn_wrupdate(struct pcm_channel *c) 420 { 421 422 CHN_LOCKASSERT(c); 423 KASSERT(c->direction == PCMDIR_PLAY, ("%s(): bad channel", __func__)); 424 425 if ((c->flags & (CHN_F_MMAP | CHN_F_VIRTUAL)) || CHN_STOPPED(c)) 426 return; 427 chn_dmaupdate(c); 428 chn_wrfeed(c); 429 /* tell the driver we've updated the primary buffer */ 430 chn_trigger(c, PCMTRIG_EMLDMAWR); 431 } 432 #endif 433 434 static void 435 chn_wrintr(struct pcm_channel *c) 436 { 437 438 CHN_LOCKASSERT(c); 439 /* update pointers in primary buffer */ 440 chn_dmaupdate(c); 441 /* ...and feed from secondary to primary */ 442 chn_wrfeed(c); 443 /* tell the driver we've updated the primary buffer */ 444 chn_trigger(c, PCMTRIG_EMLDMAWR); 445 } 446 447 /* 448 * user write routine - uiomove data into secondary buffer, trigger if necessary 449 * if blocking, sleep, rinse and repeat. 450 * 451 * called externally, so must handle locking 452 */ 453 454 int 455 chn_write(struct pcm_channel *c, struct uio *buf) 456 { 457 struct snd_dbuf *bs = c->bufsoft; 458 void *off; 459 int ret, timeout, sz, t, p; 460 461 CHN_LOCKASSERT(c); 462 463 ret = 0; 464 timeout = chn_timeout * hz; 465 466 while (ret == 0 && buf->uio_resid > 0) { 467 sz = min(buf->uio_resid, sndbuf_getfree(bs)); 468 if (sz > 0) { 469 /* 470 * The following assumes that the free space in 471 * the buffer can never be less around the 472 * unlock-uiomove-lock sequence. 473 */ 474 while (ret == 0 && sz > 0) { 475 p = sndbuf_getfreeptr(bs); 476 t = min(sz, sndbuf_getsize(bs) - p); 477 off = sndbuf_getbufofs(bs, p); 478 CHN_UNLOCK(c); 479 ret = uiomove(off, t, buf); 480 CHN_LOCK(c); 481 sz -= t; 482 sndbuf_acquire(bs, NULL, t); 483 } 484 ret = 0; 485 if (CHN_STOPPED(c) && !(c->flags & CHN_F_NOTRIGGER)) { 486 ret = chn_start(c, 0); 487 if (ret != 0) 488 c->flags |= CHN_F_DEAD; 489 } 490 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) { 491 /** 492 * @todo Evaluate whether EAGAIN is truly desirable. 493 * 4Front drivers behave like this, but I'm 494 * not sure if it at all violates the "write 495 * should be allowed to block" model. 496 * 497 * The idea is that, while set with CHN_F_NOTRIGGER, 498 * a channel isn't playing, *but* without this we 499 * end up with "interrupt timeout / channel dead". 500 */ 501 ret = EAGAIN; 502 } else { 503 ret = chn_sleep(c, timeout); 504 if (ret == EAGAIN) { 505 ret = EINVAL; 506 c->flags |= CHN_F_DEAD; 507 device_printf(c->dev, "%s(): %s: " 508 "play interrupt timeout, channel dead\n", 509 __func__, c->name); 510 } else if (ret == ERESTART || ret == EINTR) 511 c->flags |= CHN_F_ABORTING; 512 } 513 } 514 515 return (ret); 516 } 517 518 /* 519 * Feed new data from the read buffer. Can be called in the bottom half. 520 */ 521 static void 522 chn_rdfeed(struct pcm_channel *c) 523 { 524 struct snd_dbuf *b = c->bufhard; 525 struct snd_dbuf *bs = c->bufsoft; 526 unsigned int amt; 527 528 CHN_LOCKASSERT(c); 529 530 if (c->flags & CHN_F_MMAP) 531 sndbuf_dispose(bs, NULL, sndbuf_getready(bs)); 532 533 amt = sndbuf_getfree(bs); 534 if (amt > 0) 535 sndbuf_feed(b, bs, c, c->feeder, amt); 536 537 amt = sndbuf_getready(b); 538 if (amt > 0) { 539 c->xruns++; 540 sndbuf_dispose(b, NULL, amt); 541 } 542 543 if (sndbuf_getready(bs) > 0) 544 chn_wakeup(c); 545 } 546 547 #if 0 548 static void 549 chn_rdupdate(struct pcm_channel *c) 550 { 551 552 CHN_LOCKASSERT(c); 553 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel")); 554 555 if ((c->flags & (CHN_F_MMAP | CHN_F_VIRTUAL)) || CHN_STOPPED(c)) 556 return; 557 chn_trigger(c, PCMTRIG_EMLDMARD); 558 chn_dmaupdate(c); 559 chn_rdfeed(c); 560 } 561 #endif 562 563 /* read interrupt routine. Must be called with interrupts blocked. */ 564 static void 565 chn_rdintr(struct pcm_channel *c) 566 { 567 568 CHN_LOCKASSERT(c); 569 /* tell the driver to update the primary buffer if non-dma */ 570 chn_trigger(c, PCMTRIG_EMLDMARD); 571 /* update pointers in primary buffer */ 572 chn_dmaupdate(c); 573 /* ...and feed from primary to secondary */ 574 chn_rdfeed(c); 575 } 576 577 /* 578 * user read routine - trigger if necessary, uiomove data from secondary buffer 579 * if blocking, sleep, rinse and repeat. 580 * 581 * called externally, so must handle locking 582 */ 583 584 int 585 chn_read(struct pcm_channel *c, struct uio *buf) 586 { 587 struct snd_dbuf *bs = c->bufsoft; 588 void *off; 589 int ret, timeout, sz, t, p; 590 591 CHN_LOCKASSERT(c); 592 593 if (CHN_STOPPED(c) && !(c->flags & CHN_F_NOTRIGGER)) { 594 ret = chn_start(c, 0); 595 if (ret != 0) { 596 c->flags |= CHN_F_DEAD; 597 return (ret); 598 } 599 } 600 601 ret = 0; 602 timeout = chn_timeout * hz; 603 604 while (ret == 0 && buf->uio_resid > 0) { 605 sz = min(buf->uio_resid, sndbuf_getready(bs)); 606 if (sz > 0) { 607 /* 608 * The following assumes that the free space in 609 * the buffer can never be less around the 610 * unlock-uiomove-lock sequence. 611 */ 612 while (ret == 0 && sz > 0) { 613 p = sndbuf_getreadyptr(bs); 614 t = min(sz, sndbuf_getsize(bs) - p); 615 off = sndbuf_getbufofs(bs, p); 616 CHN_UNLOCK(c); 617 ret = uiomove(off, t, buf); 618 CHN_LOCK(c); 619 sz -= t; 620 sndbuf_dispose(bs, NULL, t); 621 } 622 ret = 0; 623 } else if (c->flags & (CHN_F_NBIO | CHN_F_NOTRIGGER)) 624 ret = EAGAIN; 625 else { 626 ret = chn_sleep(c, timeout); 627 if (ret == EAGAIN) { 628 ret = EINVAL; 629 c->flags |= CHN_F_DEAD; 630 device_printf(c->dev, "%s(): %s: " 631 "record interrupt timeout, channel dead\n", 632 __func__, c->name); 633 } else if (ret == ERESTART || ret == EINTR) 634 c->flags |= CHN_F_ABORTING; 635 } 636 } 637 638 return (ret); 639 } 640 641 void 642 chn_intr_locked(struct pcm_channel *c) 643 { 644 645 CHN_LOCKASSERT(c); 646 647 c->interrupts++; 648 649 if (c->direction == PCMDIR_PLAY) 650 chn_wrintr(c); 651 else 652 chn_rdintr(c); 653 } 654 655 void 656 chn_intr(struct pcm_channel *c) 657 { 658 659 if (CHN_LOCKOWNED(c)) { 660 chn_intr_locked(c); 661 return; 662 } 663 664 CHN_LOCK(c); 665 chn_intr_locked(c); 666 CHN_UNLOCK(c); 667 } 668 669 u_int32_t 670 chn_start(struct pcm_channel *c, int force) 671 { 672 u_int32_t i, j; 673 struct snd_dbuf *b = c->bufhard; 674 struct snd_dbuf *bs = c->bufsoft; 675 int err; 676 677 CHN_LOCKASSERT(c); 678 /* if we're running, or if we're prevented from triggering, bail */ 679 if (CHN_STARTED(c) || ((c->flags & CHN_F_NOTRIGGER) && !force)) 680 return (EINVAL); 681 682 err = 0; 683 684 if (force) { 685 i = 1; 686 j = 0; 687 } else { 688 if (c->direction == PCMDIR_REC) { 689 i = sndbuf_getfree(bs); 690 j = (i > 0) ? 1 : sndbuf_getready(b); 691 } else { 692 if (sndbuf_getfree(bs) == 0) { 693 i = 1; 694 j = 0; 695 } else { 696 struct snd_dbuf *pb; 697 698 pb = CHN_BUF_PARENT(c, b); 699 i = sndbuf_xbytes(sndbuf_getready(bs), bs, pb); 700 j = sndbuf_getalign(pb); 701 } 702 } 703 if (snd_verbose > 3 && CHN_EMPTY(c, children)) 704 device_printf(c->dev, "%s(): %s (%s) threshold " 705 "i=%d j=%d\n", __func__, CHN_DIRSTR(c), 706 (c->flags & CHN_F_VIRTUAL) ? "virtual" : 707 "hardware", i, j); 708 } 709 710 if (i >= j) { 711 c->flags |= CHN_F_TRIGGERED; 712 sndbuf_setrun(b, 1); 713 if (c->flags & CHN_F_CLOSING) 714 c->feedcount = 2; 715 else { 716 c->feedcount = 0; 717 c->interrupts = 0; 718 c->xruns = 0; 719 } 720 if (c->parentchannel == NULL) { 721 if (c->direction == PCMDIR_PLAY) 722 sndbuf_fillsilence_rl(b, 723 sndbuf_xbytes(sndbuf_getsize(bs), bs, b)); 724 if (snd_verbose > 3) 725 device_printf(c->dev, 726 "%s(): %s starting! (%s/%s) " 727 "(ready=%d force=%d i=%d j=%d " 728 "intrtimeout=%u latency=%dms)\n", 729 __func__, 730 (c->flags & CHN_F_HAS_VCHAN) ? 731 "VCHAN PARENT" : "HW", CHN_DIRSTR(c), 732 (c->flags & CHN_F_CLOSING) ? "closing" : 733 "running", 734 sndbuf_getready(b), 735 force, i, j, c->timeout, 736 (sndbuf_getsize(b) * 1000) / 737 (sndbuf_getalign(b) * sndbuf_getspd(b))); 738 } 739 err = chn_trigger(c, PCMTRIG_START); 740 } 741 742 return (err); 743 } 744 745 void 746 chn_resetbuf(struct pcm_channel *c) 747 { 748 struct snd_dbuf *b = c->bufhard; 749 struct snd_dbuf *bs = c->bufsoft; 750 751 c->blocks = 0; 752 sndbuf_reset(b); 753 sndbuf_reset(bs); 754 } 755 756 /* 757 * chn_sync waits until the space in the given channel goes above 758 * a threshold. The threshold is checked against fl or rl respectively. 759 * Assume that the condition can become true, do not check here... 760 */ 761 int 762 chn_sync(struct pcm_channel *c, int threshold) 763 { 764 struct snd_dbuf *b, *bs; 765 int ret, count, hcount, minflush, resid, residp, syncdelay, blksz; 766 u_int32_t cflag; 767 768 CHN_LOCKASSERT(c); 769 770 if (c->direction != PCMDIR_PLAY) 771 return (EINVAL); 772 773 bs = c->bufsoft; 774 775 if ((c->flags & (CHN_F_DEAD | CHN_F_ABORTING)) || 776 (threshold < 1 && sndbuf_getready(bs) < 1)) 777 return (0); 778 779 /* if we haven't yet started and nothing is buffered, else start*/ 780 if (CHN_STOPPED(c)) { 781 if (threshold > 0 || sndbuf_getready(bs) > 0) { 782 ret = chn_start(c, 1); 783 if (ret != 0) 784 return (ret); 785 } else 786 return (0); 787 } 788 789 b = CHN_BUF_PARENT(c, c->bufhard); 790 791 minflush = threshold + sndbuf_xbytes(sndbuf_getready(b), b, bs); 792 793 syncdelay = chn_syncdelay; 794 795 if (syncdelay < 0 && (threshold > 0 || sndbuf_getready(bs) > 0)) 796 minflush += sndbuf_xbytes(sndbuf_getsize(b), b, bs); 797 798 /* 799 * Append (0-1000) millisecond trailing buffer (if needed) 800 * for slower / high latency hardwares (notably USB audio) 801 * to avoid audible truncation. 802 */ 803 if (syncdelay > 0) 804 minflush += (sndbuf_getalign(bs) * sndbuf_getspd(bs) * 805 ((syncdelay > 1000) ? 1000 : syncdelay)) / 1000; 806 807 minflush -= minflush % sndbuf_getalign(bs); 808 809 if (minflush > 0) { 810 threshold = min(minflush, sndbuf_getfree(bs)); 811 sndbuf_clear(bs, threshold); 812 sndbuf_acquire(bs, NULL, threshold); 813 minflush -= threshold; 814 } 815 816 resid = sndbuf_getready(bs); 817 residp = resid; 818 blksz = sndbuf_getblksz(b); 819 if (blksz < 1) { 820 device_printf(c->dev, 821 "%s(): WARNING: blksz < 1 ! maxsize=%d [%d/%d/%d]\n", 822 __func__, sndbuf_getmaxsize(b), sndbuf_getsize(b), 823 sndbuf_getblksz(b), sndbuf_getblkcnt(b)); 824 if (sndbuf_getblkcnt(b) > 0) 825 blksz = sndbuf_getsize(b) / sndbuf_getblkcnt(b); 826 if (blksz < 1) 827 blksz = 1; 828 } 829 count = sndbuf_xbytes(minflush + resid, bs, b) / blksz; 830 hcount = count; 831 ret = 0; 832 833 if (snd_verbose > 3) 834 device_printf(c->dev, "%s(): [begin] timeout=%d count=%d " 835 "minflush=%d resid=%d\n", __func__, c->timeout, count, 836 minflush, resid); 837 838 cflag = c->flags & CHN_F_CLOSING; 839 c->flags |= CHN_F_CLOSING; 840 while (count > 0 && (resid > 0 || minflush > 0)) { 841 ret = chn_sleep(c, c->timeout); 842 if (ret == ERESTART || ret == EINTR) { 843 c->flags |= CHN_F_ABORTING; 844 break; 845 } else if (ret == 0 || ret == EAGAIN) { 846 resid = sndbuf_getready(bs); 847 if (resid == residp) { 848 --count; 849 if (snd_verbose > 3) 850 device_printf(c->dev, 851 "%s(): [stalled] timeout=%d " 852 "count=%d hcount=%d " 853 "resid=%d minflush=%d\n", 854 __func__, c->timeout, count, 855 hcount, resid, minflush); 856 } else if (resid < residp && count < hcount) { 857 ++count; 858 if (snd_verbose > 3) 859 device_printf(c->dev, 860 "%s((): [resume] timeout=%d " 861 "count=%d hcount=%d " 862 "resid=%d minflush=%d\n", 863 __func__, c->timeout, count, 864 hcount, resid, minflush); 865 } 866 if (minflush > 0 && sndbuf_getfree(bs) > 0) { 867 threshold = min(minflush, 868 sndbuf_getfree(bs)); 869 sndbuf_clear(bs, threshold); 870 sndbuf_acquire(bs, NULL, threshold); 871 resid = sndbuf_getready(bs); 872 minflush -= threshold; 873 } 874 residp = resid; 875 } else 876 break; 877 } 878 c->flags &= ~CHN_F_CLOSING; 879 c->flags |= cflag; 880 881 if (snd_verbose > 3) 882 device_printf(c->dev, 883 "%s(): timeout=%d count=%d hcount=%d resid=%d residp=%d " 884 "minflush=%d ret=%d\n", 885 __func__, c->timeout, count, hcount, resid, residp, 886 minflush, ret); 887 888 return (0); 889 } 890 891 /* called externally, handle locking */ 892 int 893 chn_poll(struct pcm_channel *c, int ev, struct thread *td) 894 { 895 struct snd_dbuf *bs = c->bufsoft; 896 int ret; 897 898 CHN_LOCKASSERT(c); 899 900 if (!(c->flags & (CHN_F_MMAP | CHN_F_TRIGGERED))) { 901 ret = chn_start(c, 1); 902 if (ret != 0) 903 return (0); 904 } 905 906 ret = 0; 907 if (chn_polltrigger(c)) { 908 chn_pollreset(c); 909 ret = ev; 910 } else 911 selrecord(td, sndbuf_getsel(bs)); 912 913 return (ret); 914 } 915 916 /* 917 * chn_abort terminates a running dma transfer. it may sleep up to 200ms. 918 * it returns the number of bytes that have not been transferred. 919 * 920 * called from: dsp_close, dsp_ioctl, with channel locked 921 */ 922 int 923 chn_abort(struct pcm_channel *c) 924 { 925 int missing = 0; 926 struct snd_dbuf *b = c->bufhard; 927 struct snd_dbuf *bs = c->bufsoft; 928 929 CHN_LOCKASSERT(c); 930 if (CHN_STOPPED(c)) 931 return 0; 932 c->flags |= CHN_F_ABORTING; 933 934 c->flags &= ~CHN_F_TRIGGERED; 935 /* kill the channel */ 936 chn_trigger(c, PCMTRIG_ABORT); 937 sndbuf_setrun(b, 0); 938 if (!(c->flags & CHN_F_VIRTUAL)) 939 chn_dmaupdate(c); 940 missing = sndbuf_getready(bs); 941 942 c->flags &= ~CHN_F_ABORTING; 943 return missing; 944 } 945 946 /* 947 * this routine tries to flush the dma transfer. It is called 948 * on a close of a playback channel. 949 * first, if there is data in the buffer, but the dma has not yet 950 * begun, we need to start it. 951 * next, we wait for the play buffer to drain 952 * finally, we stop the dma. 953 * 954 * called from: dsp_close, not valid for record channels. 955 */ 956 957 int 958 chn_flush(struct pcm_channel *c) 959 { 960 struct snd_dbuf *b = c->bufhard; 961 962 CHN_LOCKASSERT(c); 963 KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel")); 964 DEB(printf("chn_flush: c->flags 0x%08x\n", c->flags)); 965 966 c->flags |= CHN_F_CLOSING; 967 chn_sync(c, 0); 968 c->flags &= ~CHN_F_TRIGGERED; 969 /* kill the channel */ 970 chn_trigger(c, PCMTRIG_ABORT); 971 sndbuf_setrun(b, 0); 972 973 c->flags &= ~CHN_F_CLOSING; 974 return 0; 975 } 976 977 int 978 snd_fmtvalid(uint32_t fmt, uint32_t *fmtlist) 979 { 980 int i; 981 982 for (i = 0; fmtlist[i] != 0; i++) { 983 if (fmt == fmtlist[i] || 984 ((fmt & AFMT_PASSTHROUGH) && 985 (AFMT_ENCODING(fmt) & fmtlist[i]))) 986 return (1); 987 } 988 989 return (0); 990 } 991 992 static const struct { 993 char *name, *alias1, *alias2; 994 uint32_t afmt; 995 } afmt_tab[] = { 996 { "alaw", NULL, NULL, AFMT_A_LAW }, 997 { "mulaw", NULL, NULL, AFMT_MU_LAW }, 998 { "u8", "8", NULL, AFMT_U8 }, 999 { "s8", NULL, NULL, AFMT_S8 }, 1000 #if BYTE_ORDER == LITTLE_ENDIAN 1001 { "s16le", "s16", "16", AFMT_S16_LE }, 1002 { "s16be", NULL, NULL, AFMT_S16_BE }, 1003 #else 1004 { "s16le", NULL, NULL, AFMT_S16_LE }, 1005 { "s16be", "s16", "16", AFMT_S16_BE }, 1006 #endif 1007 { "u16le", NULL, NULL, AFMT_U16_LE }, 1008 { "u16be", NULL, NULL, AFMT_U16_BE }, 1009 { "s24le", NULL, NULL, AFMT_S24_LE }, 1010 { "s24be", NULL, NULL, AFMT_S24_BE }, 1011 { "u24le", NULL, NULL, AFMT_U24_LE }, 1012 { "u24be", NULL, NULL, AFMT_U24_BE }, 1013 #if BYTE_ORDER == LITTLE_ENDIAN 1014 { "s32le", "s32", "32", AFMT_S32_LE }, 1015 { "s32be", NULL, NULL, AFMT_S32_BE }, 1016 #else 1017 { "s32le", NULL, NULL, AFMT_S32_LE }, 1018 { "s32be", "s32", "32", AFMT_S32_BE }, 1019 #endif 1020 { "u32le", NULL, NULL, AFMT_U32_LE }, 1021 { "u32be", NULL, NULL, AFMT_U32_BE }, 1022 { "ac3", NULL, NULL, AFMT_AC3 }, 1023 { NULL, NULL, NULL, 0 } 1024 }; 1025 1026 uint32_t 1027 snd_str2afmt(const char *req) 1028 { 1029 int ext; 1030 int ch; 1031 int i; 1032 char b1[8]; 1033 char b2[8]; 1034 1035 memset(b1, 0, sizeof(b1)); 1036 memset(b2, 0, sizeof(b2)); 1037 1038 i = sscanf(req, "%5[^:]:%6s", b1, b2); 1039 1040 if (i == 1) { 1041 if (strlen(req) != strlen(b1)) 1042 return (0); 1043 strlcpy(b2, "2.0", sizeof(b2)); 1044 } else if (i == 2) { 1045 if (strlen(req) != (strlen(b1) + 1 + strlen(b2))) 1046 return (0); 1047 } else 1048 return (0); 1049 1050 i = sscanf(b2, "%d.%d", &ch, &ext); 1051 1052 if (i == 0) { 1053 if (strcasecmp(b2, "mono") == 0) { 1054 ch = 1; 1055 ext = 0; 1056 } else if (strcasecmp(b2, "stereo") == 0) { 1057 ch = 2; 1058 ext = 0; 1059 } else if (strcasecmp(b2, "quad") == 0) { 1060 ch = 4; 1061 ext = 0; 1062 } else 1063 return (0); 1064 } else if (i == 1) { 1065 if (ch < 1 || ch > AFMT_CHANNEL_MAX) 1066 return (0); 1067 ext = 0; 1068 } else if (i == 2) { 1069 if (ext < 0 || ext > AFMT_EXTCHANNEL_MAX) 1070 return (0); 1071 if (ch < 1 || (ch + ext) > AFMT_CHANNEL_MAX) 1072 return (0); 1073 } else 1074 return (0); 1075 1076 for (i = 0; afmt_tab[i].name != NULL; i++) { 1077 if (strcasecmp(afmt_tab[i].name, b1) != 0) { 1078 if (afmt_tab[i].alias1 == NULL) 1079 continue; 1080 if (strcasecmp(afmt_tab[i].alias1, b1) != 0) { 1081 if (afmt_tab[i].alias2 == NULL) 1082 continue; 1083 if (strcasecmp(afmt_tab[i].alias2, b1) != 0) 1084 continue; 1085 } 1086 } 1087 /* found a match */ 1088 return (SND_FORMAT(afmt_tab[i].afmt, ch + ext, ext)); 1089 } 1090 /* not a valid format */ 1091 return (0); 1092 } 1093 1094 uint32_t 1095 snd_afmt2str(uint32_t afmt, char *buf, size_t len) 1096 { 1097 uint32_t enc; 1098 uint32_t ext; 1099 uint32_t ch; 1100 int i; 1101 1102 if (buf == NULL || len < AFMTSTR_LEN) 1103 return (0); 1104 1105 memset(buf, 0, len); 1106 1107 enc = AFMT_ENCODING(afmt); 1108 ch = AFMT_CHANNEL(afmt); 1109 ext = AFMT_EXTCHANNEL(afmt); 1110 /* check there is at least one channel */ 1111 if (ch <= ext) 1112 return (0); 1113 for (i = 0; afmt_tab[i].name != NULL; i++) { 1114 if (enc != afmt_tab[i].afmt) 1115 continue; 1116 /* found a match */ 1117 snprintf(buf, len, "%s:%d.%d", 1118 afmt_tab[i].name, ch - ext, ext); 1119 return (SND_FORMAT(enc, ch, ext)); 1120 } 1121 return (0); 1122 } 1123 1124 int 1125 chn_reset(struct pcm_channel *c, uint32_t fmt, uint32_t spd) 1126 { 1127 int r; 1128 1129 CHN_LOCKASSERT(c); 1130 c->feedcount = 0; 1131 c->flags &= CHN_F_RESET; 1132 c->interrupts = 0; 1133 c->timeout = 1; 1134 c->xruns = 0; 1135 1136 c->flags |= (pcm_getflags(c->dev) & SD_F_BITPERFECT) ? 1137 CHN_F_BITPERFECT : 0; 1138 1139 r = CHANNEL_RESET(c->methods, c->devinfo); 1140 if (r == 0 && fmt != 0 && spd != 0) { 1141 r = chn_setparam(c, fmt, spd); 1142 fmt = 0; 1143 spd = 0; 1144 } 1145 if (r == 0 && fmt != 0) 1146 r = chn_setformat(c, fmt); 1147 if (r == 0 && spd != 0) 1148 r = chn_setspeed(c, spd); 1149 if (r == 0) 1150 r = chn_setlatency(c, chn_latency); 1151 if (r == 0) { 1152 chn_resetbuf(c); 1153 r = CHANNEL_RESETDONE(c->methods, c->devinfo); 1154 } 1155 return r; 1156 } 1157 1158 int 1159 chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction) 1160 { 1161 struct feeder_class *fc; 1162 struct snd_dbuf *b, *bs; 1163 int i, ret; 1164 1165 if (chn_timeout < CHN_TIMEOUT_MIN || chn_timeout > CHN_TIMEOUT_MAX) 1166 chn_timeout = CHN_TIMEOUT; 1167 1168 chn_lockinit(c, dir); 1169 1170 b = NULL; 1171 bs = NULL; 1172 CHN_INIT(c, children); 1173 CHN_INIT(c, children.busy); 1174 c->devinfo = NULL; 1175 c->feeder = NULL; 1176 c->latency = -1; 1177 c->timeout = 1; 1178 1179 ret = ENOMEM; 1180 b = sndbuf_create(c->dev, c->name, "primary", c); 1181 if (b == NULL) 1182 goto out; 1183 bs = sndbuf_create(c->dev, c->name, "secondary", c); 1184 if (bs == NULL) 1185 goto out; 1186 1187 CHN_LOCK(c); 1188 1189 ret = EINVAL; 1190 fc = feeder_getclass(NULL); 1191 if (fc == NULL) 1192 goto out; 1193 if (chn_addfeeder(c, fc, NULL)) 1194 goto out; 1195 1196 /* 1197 * XXX - sndbuf_setup() & sndbuf_resize() expect to be called 1198 * with the channel unlocked because they are also called 1199 * from driver methods that don't know about locking 1200 */ 1201 CHN_UNLOCK(c); 1202 sndbuf_setup(bs, NULL, 0); 1203 CHN_LOCK(c); 1204 c->bufhard = b; 1205 c->bufsoft = bs; 1206 c->flags = 0; 1207 c->feederflags = 0; 1208 c->sm = NULL; 1209 c->format = SND_FORMAT(AFMT_U8, 1, 0); 1210 c->speed = DSP_DEFAULT_SPEED; 1211 1212 c->matrix = *feeder_matrix_id_map(SND_CHN_MATRIX_1_0); 1213 c->matrix.id = SND_CHN_MATRIX_PCMCHANNEL; 1214 1215 for (i = 0; i < SND_CHN_T_MAX; i++) { 1216 c->volume[SND_VOL_C_MASTER][i] = SND_VOL_0DB_MASTER; 1217 } 1218 1219 c->volume[SND_VOL_C_MASTER][SND_CHN_T_VOL_0DB] = SND_VOL_0DB_MASTER; 1220 c->volume[SND_VOL_C_PCM][SND_CHN_T_VOL_0DB] = chn_vol_0db_pcm; 1221 1222 memset(c->muted, 0, sizeof(c->muted)); 1223 1224 chn_vpc_reset(c, SND_VOL_C_PCM, 1); 1225 1226 ret = ENODEV; 1227 CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() malloc() call */ 1228 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction); 1229 CHN_LOCK(c); 1230 if (c->devinfo == NULL) 1231 goto out; 1232 1233 ret = ENOMEM; 1234 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0)) 1235 goto out; 1236 1237 ret = 0; 1238 c->direction = direction; 1239 1240 sndbuf_setfmt(b, c->format); 1241 sndbuf_setspd(b, c->speed); 1242 sndbuf_setfmt(bs, c->format); 1243 sndbuf_setspd(bs, c->speed); 1244 1245 /** 1246 * @todo Should this be moved somewhere else? The primary buffer 1247 * is allocated by the driver or via DMA map setup, and tmpbuf 1248 * seems to only come into existence in sndbuf_resize(). 1249 */ 1250 if (c->direction == PCMDIR_PLAY) { 1251 bs->sl = sndbuf_getmaxsize(bs); 1252 bs->shadbuf = malloc(bs->sl, M_DEVBUF, M_NOWAIT); 1253 if (bs->shadbuf == NULL) { 1254 ret = ENOMEM; 1255 goto out; 1256 } 1257 } 1258 1259 out: 1260 CHN_UNLOCK(c); 1261 if (ret) { 1262 if (c->devinfo) { 1263 if (CHANNEL_FREE(c->methods, c->devinfo)) 1264 sndbuf_free(b); 1265 } 1266 if (bs) 1267 sndbuf_destroy(bs); 1268 if (b) 1269 sndbuf_destroy(b); 1270 CHN_LOCK(c); 1271 c->flags |= CHN_F_DEAD; 1272 chn_lockdestroy(c); 1273 1274 return ret; 1275 } 1276 1277 return 0; 1278 } 1279 1280 int 1281 chn_kill(struct pcm_channel *c) 1282 { 1283 struct snd_dbuf *b = c->bufhard; 1284 struct snd_dbuf *bs = c->bufsoft; 1285 1286 if (CHN_STARTED(c)) { 1287 CHN_LOCK(c); 1288 chn_trigger(c, PCMTRIG_ABORT); 1289 CHN_UNLOCK(c); 1290 } 1291 while (chn_removefeeder(c) == 0) 1292 ; 1293 if (CHANNEL_FREE(c->methods, c->devinfo)) 1294 sndbuf_free(b); 1295 sndbuf_destroy(bs); 1296 sndbuf_destroy(b); 1297 CHN_LOCK(c); 1298 c->flags |= CHN_F_DEAD; 1299 chn_lockdestroy(c); 1300 1301 return (0); 1302 } 1303 1304 /* XXX Obsolete. Use *_matrix() variant instead. */ 1305 int 1306 chn_setvolume(struct pcm_channel *c, int left, int right) 1307 { 1308 int ret; 1309 1310 ret = chn_setvolume_matrix(c, SND_VOL_C_MASTER, SND_CHN_T_FL, left); 1311 ret |= chn_setvolume_matrix(c, SND_VOL_C_MASTER, SND_CHN_T_FR, 1312 right) << 8; 1313 1314 return (ret); 1315 } 1316 1317 int 1318 chn_setvolume_multi(struct pcm_channel *c, int vc, int left, int right, 1319 int center) 1320 { 1321 int i, ret; 1322 1323 ret = 0; 1324 1325 for (i = 0; i < SND_CHN_T_MAX; i++) { 1326 if ((1 << i) & SND_CHN_LEFT_MASK) 1327 ret |= chn_setvolume_matrix(c, vc, i, left); 1328 else if ((1 << i) & SND_CHN_RIGHT_MASK) 1329 ret |= chn_setvolume_matrix(c, vc, i, right) << 8; 1330 else 1331 ret |= chn_setvolume_matrix(c, vc, i, center) << 16; 1332 } 1333 1334 return (ret); 1335 } 1336 1337 int 1338 chn_setvolume_matrix(struct pcm_channel *c, int vc, int vt, int val) 1339 { 1340 int i; 1341 1342 KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX && 1343 (vc == SND_VOL_C_MASTER || (vc & 1)) && 1344 (vt == SND_CHN_T_VOL_0DB || (vt >= SND_CHN_T_BEGIN && 1345 vt <= SND_CHN_T_END)) && (vt != SND_CHN_T_VOL_0DB || 1346 (val >= SND_VOL_0DB_MIN && val <= SND_VOL_0DB_MAX)), 1347 ("%s(): invalid volume matrix c=%p vc=%d vt=%d val=%d", 1348 __func__, c, vc, vt, val)); 1349 CHN_LOCKASSERT(c); 1350 1351 if (val < 0) 1352 val = 0; 1353 if (val > 100) 1354 val = 100; 1355 1356 c->volume[vc][vt] = val; 1357 1358 /* 1359 * Do relative calculation here and store it into class + 1 1360 * to ease the job of feeder_volume. 1361 */ 1362 if (vc == SND_VOL_C_MASTER) { 1363 for (vc = SND_VOL_C_BEGIN; vc <= SND_VOL_C_END; 1364 vc += SND_VOL_C_STEP) 1365 c->volume[SND_VOL_C_VAL(vc)][vt] = 1366 SND_VOL_CALC_VAL(c->volume, vc, vt); 1367 } else if (vc & 1) { 1368 if (vt == SND_CHN_T_VOL_0DB) 1369 for (i = SND_CHN_T_BEGIN; i <= SND_CHN_T_END; 1370 i += SND_CHN_T_STEP) { 1371 c->volume[SND_VOL_C_VAL(vc)][i] = 1372 SND_VOL_CALC_VAL(c->volume, vc, i); 1373 } 1374 else 1375 c->volume[SND_VOL_C_VAL(vc)][vt] = 1376 SND_VOL_CALC_VAL(c->volume, vc, vt); 1377 } 1378 1379 return (val); 1380 } 1381 1382 int 1383 chn_getvolume_matrix(struct pcm_channel *c, int vc, int vt) 1384 { 1385 KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX && 1386 (vt == SND_CHN_T_VOL_0DB || 1387 (vt >= SND_CHN_T_BEGIN && vt <= SND_CHN_T_END)), 1388 ("%s(): invalid volume matrix c=%p vc=%d vt=%d", 1389 __func__, c, vc, vt)); 1390 CHN_LOCKASSERT(c); 1391 1392 return (c->volume[vc][vt]); 1393 } 1394 1395 int 1396 chn_setmute_multi(struct pcm_channel *c, int vc, int mute) 1397 { 1398 int i, ret; 1399 1400 ret = 0; 1401 1402 for (i = 0; i < SND_CHN_T_MAX; i++) { 1403 if ((1 << i) & SND_CHN_LEFT_MASK) 1404 ret |= chn_setmute_matrix(c, vc, i, mute); 1405 else if ((1 << i) & SND_CHN_RIGHT_MASK) 1406 ret |= chn_setmute_matrix(c, vc, i, mute) << 8; 1407 else 1408 ret |= chn_setmute_matrix(c, vc, i, mute) << 16; 1409 } 1410 return (ret); 1411 } 1412 1413 int 1414 chn_setmute_matrix(struct pcm_channel *c, int vc, int vt, int mute) 1415 { 1416 int i; 1417 1418 KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX && 1419 (vc == SND_VOL_C_MASTER || (vc & 1)) && 1420 (vt == SND_CHN_T_VOL_0DB || (vt >= SND_CHN_T_BEGIN && vt <= SND_CHN_T_END)), 1421 ("%s(): invalid mute matrix c=%p vc=%d vt=%d mute=%d", 1422 __func__, c, vc, vt, mute)); 1423 1424 CHN_LOCKASSERT(c); 1425 1426 mute = (mute != 0); 1427 1428 c->muted[vc][vt] = mute; 1429 1430 /* 1431 * Do relative calculation here and store it into class + 1 1432 * to ease the job of feeder_volume. 1433 */ 1434 if (vc == SND_VOL_C_MASTER) { 1435 for (vc = SND_VOL_C_BEGIN; vc <= SND_VOL_C_END; 1436 vc += SND_VOL_C_STEP) 1437 c->muted[SND_VOL_C_VAL(vc)][vt] = mute; 1438 } else if (vc & 1) { 1439 if (vt == SND_CHN_T_VOL_0DB) { 1440 for (i = SND_CHN_T_BEGIN; i <= SND_CHN_T_END; 1441 i += SND_CHN_T_STEP) { 1442 c->muted[SND_VOL_C_VAL(vc)][i] = mute; 1443 } 1444 } else { 1445 c->muted[SND_VOL_C_VAL(vc)][vt] = mute; 1446 } 1447 } 1448 return (mute); 1449 } 1450 1451 int 1452 chn_getmute_matrix(struct pcm_channel *c, int vc, int vt) 1453 { 1454 KASSERT(c != NULL && vc >= SND_VOL_C_MASTER && vc < SND_VOL_C_MAX && 1455 (vt == SND_CHN_T_VOL_0DB || 1456 (vt >= SND_CHN_T_BEGIN && vt <= SND_CHN_T_END)), 1457 ("%s(): invalid mute matrix c=%p vc=%d vt=%d", 1458 __func__, c, vc, vt)); 1459 CHN_LOCKASSERT(c); 1460 1461 return (c->muted[vc][vt]); 1462 } 1463 1464 struct pcmchan_matrix * 1465 chn_getmatrix(struct pcm_channel *c) 1466 { 1467 1468 KASSERT(c != NULL, ("%s(): NULL channel", __func__)); 1469 CHN_LOCKASSERT(c); 1470 1471 if (!(c->format & AFMT_CONVERTIBLE)) 1472 return (NULL); 1473 1474 return (&c->matrix); 1475 } 1476 1477 int 1478 chn_setmatrix(struct pcm_channel *c, struct pcmchan_matrix *m) 1479 { 1480 1481 KASSERT(c != NULL && m != NULL, 1482 ("%s(): NULL channel or matrix", __func__)); 1483 CHN_LOCKASSERT(c); 1484 1485 if (!(c->format & AFMT_CONVERTIBLE)) 1486 return (EINVAL); 1487 1488 c->matrix = *m; 1489 c->matrix.id = SND_CHN_MATRIX_PCMCHANNEL; 1490 1491 return (chn_setformat(c, SND_FORMAT(c->format, m->channels, m->ext))); 1492 } 1493 1494 /* 1495 * XXX chn_oss_* exists for the sake of compatibility. 1496 */ 1497 int 1498 chn_oss_getorder(struct pcm_channel *c, unsigned long long *map) 1499 { 1500 1501 KASSERT(c != NULL && map != NULL, 1502 ("%s(): NULL channel or map", __func__)); 1503 CHN_LOCKASSERT(c); 1504 1505 if (!(c->format & AFMT_CONVERTIBLE)) 1506 return (EINVAL); 1507 1508 return (feeder_matrix_oss_get_channel_order(&c->matrix, map)); 1509 } 1510 1511 int 1512 chn_oss_setorder(struct pcm_channel *c, unsigned long long *map) 1513 { 1514 struct pcmchan_matrix m; 1515 int ret; 1516 1517 KASSERT(c != NULL && map != NULL, 1518 ("%s(): NULL channel or map", __func__)); 1519 CHN_LOCKASSERT(c); 1520 1521 if (!(c->format & AFMT_CONVERTIBLE)) 1522 return (EINVAL); 1523 1524 m = c->matrix; 1525 ret = feeder_matrix_oss_set_channel_order(&m, map); 1526 if (ret != 0) 1527 return (ret); 1528 1529 return (chn_setmatrix(c, &m)); 1530 } 1531 1532 #define SND_CHN_OSS_FRONT (SND_CHN_T_MASK_FL | SND_CHN_T_MASK_FR) 1533 #define SND_CHN_OSS_SURR (SND_CHN_T_MASK_SL | SND_CHN_T_MASK_SR) 1534 #define SND_CHN_OSS_CENTER_LFE (SND_CHN_T_MASK_FC | SND_CHN_T_MASK_LF) 1535 #define SND_CHN_OSS_REAR (SND_CHN_T_MASK_BL | SND_CHN_T_MASK_BR) 1536 1537 int 1538 chn_oss_getmask(struct pcm_channel *c, uint32_t *retmask) 1539 { 1540 struct pcmchan_matrix *m; 1541 struct pcmchan_caps *caps; 1542 uint32_t i, format; 1543 1544 KASSERT(c != NULL && retmask != NULL, 1545 ("%s(): NULL channel or retmask", __func__)); 1546 CHN_LOCKASSERT(c); 1547 1548 caps = chn_getcaps(c); 1549 if (caps == NULL || caps->fmtlist == NULL) 1550 return (ENODEV); 1551 1552 for (i = 0; caps->fmtlist[i] != 0; i++) { 1553 format = caps->fmtlist[i]; 1554 if (!(format & AFMT_CONVERTIBLE)) { 1555 *retmask |= DSP_BIND_SPDIF; 1556 continue; 1557 } 1558 m = CHANNEL_GETMATRIX(c->methods, c->devinfo, format); 1559 if (m == NULL) 1560 continue; 1561 if (m->mask & SND_CHN_OSS_FRONT) 1562 *retmask |= DSP_BIND_FRONT; 1563 if (m->mask & SND_CHN_OSS_SURR) 1564 *retmask |= DSP_BIND_SURR; 1565 if (m->mask & SND_CHN_OSS_CENTER_LFE) 1566 *retmask |= DSP_BIND_CENTER_LFE; 1567 if (m->mask & SND_CHN_OSS_REAR) 1568 *retmask |= DSP_BIND_REAR; 1569 } 1570 1571 /* report software-supported binding mask */ 1572 if (!CHN_BITPERFECT(c) && report_soft_matrix) 1573 *retmask |= DSP_BIND_FRONT | DSP_BIND_SURR | 1574 DSP_BIND_CENTER_LFE | DSP_BIND_REAR; 1575 1576 return (0); 1577 } 1578 1579 void 1580 chn_vpc_reset(struct pcm_channel *c, int vc, int force) 1581 { 1582 int i; 1583 1584 KASSERT(c != NULL && vc >= SND_VOL_C_BEGIN && vc <= SND_VOL_C_END, 1585 ("%s(): invalid reset c=%p vc=%d", __func__, c, vc)); 1586 CHN_LOCKASSERT(c); 1587 1588 if (force == 0 && chn_vpc_autoreset == 0) 1589 return; 1590 1591 for (i = SND_CHN_T_BEGIN; i <= SND_CHN_T_END; i += SND_CHN_T_STEP) 1592 CHN_SETVOLUME(c, vc, i, c->volume[vc][SND_CHN_T_VOL_0DB]); 1593 } 1594 1595 static u_int32_t 1596 round_pow2(u_int32_t v) 1597 { 1598 u_int32_t ret; 1599 1600 if (v < 2) 1601 v = 2; 1602 ret = 0; 1603 while (v >> ret) 1604 ret++; 1605 ret = 1 << (ret - 1); 1606 while (ret < v) 1607 ret <<= 1; 1608 return ret; 1609 } 1610 1611 static u_int32_t 1612 round_blksz(u_int32_t v, int round) 1613 { 1614 u_int32_t ret, tmp; 1615 1616 if (round < 1) 1617 round = 1; 1618 1619 ret = min(round_pow2(v), CHN_2NDBUFMAXSIZE >> 1); 1620 1621 if (ret > v && (ret >> 1) > 0 && (ret >> 1) >= ((v * 3) >> 2)) 1622 ret >>= 1; 1623 1624 tmp = ret - (ret % round); 1625 while (tmp < 16 || tmp < round) { 1626 ret <<= 1; 1627 tmp = ret - (ret % round); 1628 } 1629 1630 return ret; 1631 } 1632 1633 /* 1634 * 4Front call it DSP Policy, while we call it "Latency Profile". The idea 1635 * is to keep 2nd buffer short so that it doesn't cause long queue during 1636 * buffer transfer. 1637 * 1638 * Latency reference table for 48khz stereo 16bit: (PLAY) 1639 * 1640 * +---------+------------+-----------+------------+ 1641 * | Latency | Blockcount | Blocksize | Buffersize | 1642 * +---------+------------+-----------+------------+ 1643 * | 0 | 2 | 64 | 128 | 1644 * +---------+------------+-----------+------------+ 1645 * | 1 | 4 | 128 | 512 | 1646 * +---------+------------+-----------+------------+ 1647 * | 2 | 8 | 512 | 4096 | 1648 * +---------+------------+-----------+------------+ 1649 * | 3 | 16 | 512 | 8192 | 1650 * +---------+------------+-----------+------------+ 1651 * | 4 | 32 | 512 | 16384 | 1652 * +---------+------------+-----------+------------+ 1653 * | 5 | 32 | 1024 | 32768 | 1654 * +---------+------------+-----------+------------+ 1655 * | 6 | 16 | 2048 | 32768 | 1656 * +---------+------------+-----------+------------+ 1657 * | 7 | 8 | 4096 | 32768 | 1658 * +---------+------------+-----------+------------+ 1659 * | 8 | 4 | 8192 | 32768 | 1660 * +---------+------------+-----------+------------+ 1661 * | 9 | 2 | 16384 | 32768 | 1662 * +---------+------------+-----------+------------+ 1663 * | 10 | 2 | 32768 | 65536 | 1664 * +---------+------------+-----------+------------+ 1665 * 1666 * Recording need a different reference table. All we care is 1667 * gobbling up everything within reasonable buffering threshold. 1668 * 1669 * Latency reference table for 48khz stereo 16bit: (REC) 1670 * 1671 * +---------+------------+-----------+------------+ 1672 * | Latency | Blockcount | Blocksize | Buffersize | 1673 * +---------+------------+-----------+------------+ 1674 * | 0 | 512 | 32 | 16384 | 1675 * +---------+------------+-----------+------------+ 1676 * | 1 | 256 | 64 | 16384 | 1677 * +---------+------------+-----------+------------+ 1678 * | 2 | 128 | 128 | 16384 | 1679 * +---------+------------+-----------+------------+ 1680 * | 3 | 64 | 256 | 16384 | 1681 * +---------+------------+-----------+------------+ 1682 * | 4 | 32 | 512 | 16384 | 1683 * +---------+------------+-----------+------------+ 1684 * | 5 | 32 | 1024 | 32768 | 1685 * +---------+------------+-----------+------------+ 1686 * | 6 | 16 | 2048 | 32768 | 1687 * +---------+------------+-----------+------------+ 1688 * | 7 | 8 | 4096 | 32768 | 1689 * +---------+------------+-----------+------------+ 1690 * | 8 | 4 | 8192 | 32768 | 1691 * +---------+------------+-----------+------------+ 1692 * | 9 | 2 | 16384 | 32768 | 1693 * +---------+------------+-----------+------------+ 1694 * | 10 | 2 | 32768 | 65536 | 1695 * +---------+------------+-----------+------------+ 1696 * 1697 * Calculations for other data rate are entirely based on these reference 1698 * tables. For normal operation, Latency 5 seems give the best, well 1699 * balanced performance for typical workload. Anything below 5 will 1700 * eat up CPU to keep up with increasing context switches because of 1701 * shorter buffer space and usually require the application to handle it 1702 * aggressively through possibly real time programming technique. 1703 * 1704 */ 1705 #define CHN_LATENCY_PBLKCNT_REF \ 1706 {{1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1}, \ 1707 {1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1}} 1708 #define CHN_LATENCY_PBUFSZ_REF \ 1709 {{7, 9, 12, 13, 14, 15, 15, 15, 15, 15, 16}, \ 1710 {11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 17}} 1711 1712 #define CHN_LATENCY_RBLKCNT_REF \ 1713 {{9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1}, \ 1714 {9, 8, 7, 6, 5, 5, 4, 3, 2, 1, 1}} 1715 #define CHN_LATENCY_RBUFSZ_REF \ 1716 {{14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16}, \ 1717 {15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17}} 1718 1719 #define CHN_LATENCY_DATA_REF 192000 /* 48khz stereo 16bit ~ 48000 x 2 x 2 */ 1720 1721 static int 1722 chn_calclatency(int dir, int latency, int bps, u_int32_t datarate, 1723 u_int32_t max, int *rblksz, int *rblkcnt) 1724 { 1725 static int pblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] = 1726 CHN_LATENCY_PBLKCNT_REF; 1727 static int pbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] = 1728 CHN_LATENCY_PBUFSZ_REF; 1729 static int rblkcnts[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] = 1730 CHN_LATENCY_RBLKCNT_REF; 1731 static int rbufszs[CHN_LATENCY_PROFILE_MAX + 1][CHN_LATENCY_MAX + 1] = 1732 CHN_LATENCY_RBUFSZ_REF; 1733 u_int32_t bufsz; 1734 int lprofile, blksz, blkcnt; 1735 1736 if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX || 1737 bps < 1 || datarate < 1 || 1738 !(dir == PCMDIR_PLAY || dir == PCMDIR_REC)) { 1739 if (rblksz != NULL) 1740 *rblksz = CHN_2NDBUFMAXSIZE >> 1; 1741 if (rblkcnt != NULL) 1742 *rblkcnt = 2; 1743 printf("%s(): FAILED dir=%d latency=%d bps=%d " 1744 "datarate=%u max=%u\n", 1745 __func__, dir, latency, bps, datarate, max); 1746 return CHN_2NDBUFMAXSIZE; 1747 } 1748 1749 lprofile = chn_latency_profile; 1750 1751 if (dir == PCMDIR_PLAY) { 1752 blkcnt = pblkcnts[lprofile][latency]; 1753 bufsz = pbufszs[lprofile][latency]; 1754 } else { 1755 blkcnt = rblkcnts[lprofile][latency]; 1756 bufsz = rbufszs[lprofile][latency]; 1757 } 1758 1759 bufsz = round_pow2(snd_xbytes(1 << bufsz, CHN_LATENCY_DATA_REF, 1760 datarate)); 1761 if (bufsz > max) 1762 bufsz = max; 1763 blksz = round_blksz(bufsz >> blkcnt, bps); 1764 1765 if (rblksz != NULL) 1766 *rblksz = blksz; 1767 if (rblkcnt != NULL) 1768 *rblkcnt = 1 << blkcnt; 1769 1770 return blksz << blkcnt; 1771 } 1772 1773 static int 1774 chn_resizebuf(struct pcm_channel *c, int latency, 1775 int blkcnt, int blksz) 1776 { 1777 struct snd_dbuf *b, *bs, *pb; 1778 int sblksz, sblkcnt, hblksz, hblkcnt, limit = 0, nsblksz, nsblkcnt; 1779 int ret; 1780 1781 CHN_LOCKASSERT(c); 1782 1783 if ((c->flags & (CHN_F_MMAP | CHN_F_TRIGGERED)) || 1784 !(c->direction == PCMDIR_PLAY || c->direction == PCMDIR_REC)) 1785 return EINVAL; 1786 1787 if (latency == -1) { 1788 c->latency = -1; 1789 latency = chn_latency; 1790 } else if (latency == -2) { 1791 latency = c->latency; 1792 if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX) 1793 latency = chn_latency; 1794 } else if (latency < CHN_LATENCY_MIN || latency > CHN_LATENCY_MAX) 1795 return EINVAL; 1796 else { 1797 c->latency = latency; 1798 } 1799 1800 bs = c->bufsoft; 1801 b = c->bufhard; 1802 1803 if (!(blksz == 0 || blkcnt == -1) && 1804 (blksz < 16 || blksz < sndbuf_getalign(bs) || blkcnt < 2 || 1805 (blksz * blkcnt) > CHN_2NDBUFMAXSIZE)) 1806 return EINVAL; 1807 1808 chn_calclatency(c->direction, latency, sndbuf_getalign(bs), 1809 sndbuf_getalign(bs) * sndbuf_getspd(bs), CHN_2NDBUFMAXSIZE, 1810 &sblksz, &sblkcnt); 1811 1812 if (blksz == 0 || blkcnt == -1) { 1813 if (blkcnt == -1) 1814 c->flags &= ~CHN_F_HAS_SIZE; 1815 if (c->flags & CHN_F_HAS_SIZE) { 1816 blksz = sndbuf_getblksz(bs); 1817 blkcnt = sndbuf_getblkcnt(bs); 1818 } 1819 } else 1820 c->flags |= CHN_F_HAS_SIZE; 1821 1822 if (c->flags & CHN_F_HAS_SIZE) { 1823 /* 1824 * The application has requested their own blksz/blkcnt. 1825 * Just obey with it, and let them toast alone. We can 1826 * clamp it to the nearest latency profile, but that would 1827 * defeat the purpose of having custom control. The least 1828 * we can do is round it to the nearest ^2 and align it. 1829 */ 1830 sblksz = round_blksz(blksz, sndbuf_getalign(bs)); 1831 sblkcnt = round_pow2(blkcnt); 1832 } 1833 1834 if (c->parentchannel != NULL) { 1835 pb = c->parentchannel->bufsoft; 1836 CHN_UNLOCK(c); 1837 CHN_LOCK(c->parentchannel); 1838 chn_notify(c->parentchannel, CHN_N_BLOCKSIZE); 1839 CHN_UNLOCK(c->parentchannel); 1840 CHN_LOCK(c); 1841 if (c->direction == PCMDIR_PLAY) { 1842 limit = (pb != NULL) ? 1843 sndbuf_xbytes(sndbuf_getsize(pb), pb, bs) : 0; 1844 } else { 1845 limit = (pb != NULL) ? 1846 sndbuf_xbytes(sndbuf_getblksz(pb), pb, bs) * 2 : 0; 1847 } 1848 } else { 1849 hblkcnt = 2; 1850 if (c->flags & CHN_F_HAS_SIZE) { 1851 hblksz = round_blksz(sndbuf_xbytes(sblksz, bs, b), 1852 sndbuf_getalign(b)); 1853 hblkcnt = round_pow2(sndbuf_getblkcnt(bs)); 1854 } else 1855 chn_calclatency(c->direction, latency, 1856 sndbuf_getalign(b), 1857 sndbuf_getalign(b) * sndbuf_getspd(b), 1858 CHN_2NDBUFMAXSIZE, &hblksz, &hblkcnt); 1859 1860 if ((hblksz << 1) > sndbuf_getmaxsize(b)) 1861 hblksz = round_blksz(sndbuf_getmaxsize(b) >> 1, 1862 sndbuf_getalign(b)); 1863 1864 while ((hblksz * hblkcnt) > sndbuf_getmaxsize(b)) { 1865 if (hblkcnt < 4) 1866 hblksz >>= 1; 1867 else 1868 hblkcnt >>= 1; 1869 } 1870 1871 hblksz -= hblksz % sndbuf_getalign(b); 1872 1873 #if 0 1874 hblksz = sndbuf_getmaxsize(b) >> 1; 1875 hblksz -= hblksz % sndbuf_getalign(b); 1876 hblkcnt = 2; 1877 #endif 1878 1879 CHN_UNLOCK(c); 1880 if (chn_usefrags == 0 || 1881 CHANNEL_SETFRAGMENTS(c->methods, c->devinfo, 1882 hblksz, hblkcnt) != 0) 1883 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, 1884 c->devinfo, hblksz)); 1885 CHN_LOCK(c); 1886 1887 if (!CHN_EMPTY(c, children)) { 1888 nsblksz = round_blksz( 1889 sndbuf_xbytes(sndbuf_getblksz(b), b, bs), 1890 sndbuf_getalign(bs)); 1891 nsblkcnt = sndbuf_getblkcnt(b); 1892 if (c->direction == PCMDIR_PLAY) { 1893 do { 1894 nsblkcnt--; 1895 } while (nsblkcnt >= 2 && 1896 nsblksz * nsblkcnt >= sblksz * sblkcnt); 1897 nsblkcnt++; 1898 } 1899 sblksz = nsblksz; 1900 sblkcnt = nsblkcnt; 1901 limit = 0; 1902 } else 1903 limit = sndbuf_xbytes(sndbuf_getblksz(b), b, bs) * 2; 1904 } 1905 1906 if (limit > CHN_2NDBUFMAXSIZE) 1907 limit = CHN_2NDBUFMAXSIZE; 1908 1909 #if 0 1910 while (limit > 0 && (sblksz * sblkcnt) > limit) { 1911 if (sblkcnt < 4) 1912 break; 1913 sblkcnt >>= 1; 1914 } 1915 #endif 1916 1917 while ((sblksz * sblkcnt) < limit) 1918 sblkcnt <<= 1; 1919 1920 while ((sblksz * sblkcnt) > CHN_2NDBUFMAXSIZE) { 1921 if (sblkcnt < 4) 1922 sblksz >>= 1; 1923 else 1924 sblkcnt >>= 1; 1925 } 1926 1927 sblksz -= sblksz % sndbuf_getalign(bs); 1928 1929 if (sndbuf_getblkcnt(bs) != sblkcnt || sndbuf_getblksz(bs) != sblksz || 1930 sndbuf_getsize(bs) != (sblkcnt * sblksz)) { 1931 ret = sndbuf_remalloc(bs, sblkcnt, sblksz); 1932 if (ret != 0) { 1933 device_printf(c->dev, "%s(): Failed: %d %d\n", 1934 __func__, sblkcnt, sblksz); 1935 return ret; 1936 } 1937 } 1938 1939 /* 1940 * Interrupt timeout 1941 */ 1942 c->timeout = ((u_int64_t)hz * sndbuf_getsize(bs)) / 1943 ((u_int64_t)sndbuf_getspd(bs) * sndbuf_getalign(bs)); 1944 if (c->parentchannel != NULL) 1945 c->timeout = min(c->timeout, c->parentchannel->timeout); 1946 if (c->timeout < 1) 1947 c->timeout = 1; 1948 1949 /* 1950 * OSSv4 docs: "By default OSS will set the low water level equal 1951 * to the fragment size which is optimal in most cases." 1952 */ 1953 c->lw = sndbuf_getblksz(bs); 1954 chn_resetbuf(c); 1955 1956 if (snd_verbose > 3) 1957 device_printf(c->dev, "%s(): %s (%s) timeout=%u " 1958 "b[%d/%d/%d] bs[%d/%d/%d] limit=%d\n", 1959 __func__, CHN_DIRSTR(c), 1960 (c->flags & CHN_F_VIRTUAL) ? "virtual" : "hardware", 1961 c->timeout, 1962 sndbuf_getsize(b), sndbuf_getblksz(b), 1963 sndbuf_getblkcnt(b), 1964 sndbuf_getsize(bs), sndbuf_getblksz(bs), 1965 sndbuf_getblkcnt(bs), limit); 1966 1967 return 0; 1968 } 1969 1970 int 1971 chn_setlatency(struct pcm_channel *c, int latency) 1972 { 1973 CHN_LOCKASSERT(c); 1974 /* Destroy blksz/blkcnt, enforce latency profile. */ 1975 return chn_resizebuf(c, latency, -1, 0); 1976 } 1977 1978 int 1979 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz) 1980 { 1981 CHN_LOCKASSERT(c); 1982 /* Destroy latency profile, enforce blksz/blkcnt */ 1983 return chn_resizebuf(c, -1, blkcnt, blksz); 1984 } 1985 1986 int 1987 chn_setparam(struct pcm_channel *c, uint32_t format, uint32_t speed) 1988 { 1989 struct pcmchan_caps *caps; 1990 uint32_t hwspeed, delta; 1991 int ret; 1992 1993 CHN_LOCKASSERT(c); 1994 1995 if (speed < 1 || format == 0 || CHN_STARTED(c)) 1996 return (EINVAL); 1997 1998 c->format = format; 1999 c->speed = speed; 2000 2001 caps = chn_getcaps(c); 2002 2003 hwspeed = speed; 2004 RANGE(hwspeed, caps->minspeed, caps->maxspeed); 2005 2006 sndbuf_setspd(c->bufhard, CHANNEL_SETSPEED(c->methods, c->devinfo, 2007 hwspeed)); 2008 hwspeed = sndbuf_getspd(c->bufhard); 2009 2010 delta = (hwspeed > speed) ? (hwspeed - speed) : (speed - hwspeed); 2011 2012 if (delta <= feeder_rate_round) 2013 c->speed = hwspeed; 2014 2015 ret = feeder_chain(c); 2016 2017 if (ret == 0) 2018 ret = CHANNEL_SETFORMAT(c->methods, c->devinfo, 2019 sndbuf_getfmt(c->bufhard)); 2020 2021 if (ret == 0) 2022 ret = chn_resizebuf(c, -2, 0, 0); 2023 2024 return (ret); 2025 } 2026 2027 int 2028 chn_setspeed(struct pcm_channel *c, uint32_t speed) 2029 { 2030 uint32_t oldformat, oldspeed, format; 2031 int ret; 2032 2033 #if 0 2034 /* XXX force 48k */ 2035 if (c->format & AFMT_PASSTHROUGH) 2036 speed = AFMT_PASSTHROUGH_RATE; 2037 #endif 2038 2039 oldformat = c->format; 2040 oldspeed = c->speed; 2041 format = oldformat; 2042 2043 ret = chn_setparam(c, format, speed); 2044 if (ret != 0) { 2045 if (snd_verbose > 3) 2046 device_printf(c->dev, 2047 "%s(): Setting speed %d failed, " 2048 "falling back to %d\n", 2049 __func__, speed, oldspeed); 2050 chn_setparam(c, c->format, oldspeed); 2051 } 2052 2053 return (ret); 2054 } 2055 2056 int 2057 chn_setformat(struct pcm_channel *c, uint32_t format) 2058 { 2059 uint32_t oldformat, oldspeed, speed; 2060 int ret; 2061 2062 /* XXX force stereo */ 2063 if ((format & AFMT_PASSTHROUGH) && AFMT_CHANNEL(format) < 2) { 2064 format = SND_FORMAT(format, AFMT_PASSTHROUGH_CHANNEL, 2065 AFMT_PASSTHROUGH_EXTCHANNEL); 2066 } 2067 2068 oldformat = c->format; 2069 oldspeed = c->speed; 2070 speed = oldspeed; 2071 2072 ret = chn_setparam(c, format, speed); 2073 if (ret != 0) { 2074 if (snd_verbose > 3) 2075 device_printf(c->dev, 2076 "%s(): Format change 0x%08x failed, " 2077 "falling back to 0x%08x\n", 2078 __func__, format, oldformat); 2079 chn_setparam(c, oldformat, oldspeed); 2080 } 2081 2082 return (ret); 2083 } 2084 2085 void 2086 chn_syncstate(struct pcm_channel *c) 2087 { 2088 struct snddev_info *d; 2089 struct snd_mixer *m; 2090 2091 d = (c != NULL) ? c->parentsnddev : NULL; 2092 m = (d != NULL && d->mixer_dev != NULL) ? d->mixer_dev->si_drv1 : 2093 NULL; 2094 2095 if (d == NULL || m == NULL) 2096 return; 2097 2098 CHN_LOCKASSERT(c); 2099 2100 if (c->feederflags & (1 << FEEDER_VOLUME)) { 2101 uint32_t parent; 2102 int vol, pvol, left, right, center; 2103 2104 if (c->direction == PCMDIR_PLAY && 2105 (d->flags & SD_F_SOFTPCMVOL)) { 2106 /* CHN_UNLOCK(c); */ 2107 vol = mix_get(m, SOUND_MIXER_PCM); 2108 parent = mix_getparent(m, SOUND_MIXER_PCM); 2109 if (parent != SOUND_MIXER_NONE) 2110 pvol = mix_get(m, parent); 2111 else 2112 pvol = 100 | (100 << 8); 2113 /* CHN_LOCK(c); */ 2114 } else { 2115 vol = 100 | (100 << 8); 2116 pvol = vol; 2117 } 2118 2119 if (vol == -1) { 2120 device_printf(c->dev, 2121 "Soft PCM Volume: Failed to read pcm " 2122 "default value\n"); 2123 vol = 100 | (100 << 8); 2124 } 2125 2126 if (pvol == -1) { 2127 device_printf(c->dev, 2128 "Soft PCM Volume: Failed to read parent " 2129 "default value\n"); 2130 pvol = 100 | (100 << 8); 2131 } 2132 2133 left = ((vol & 0x7f) * (pvol & 0x7f)) / 100; 2134 right = (((vol >> 8) & 0x7f) * ((pvol >> 8) & 0x7f)) / 100; 2135 center = (left + right) >> 1; 2136 2137 chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right, center); 2138 } 2139 2140 if (c->feederflags & (1 << FEEDER_EQ)) { 2141 struct pcm_feeder *f; 2142 int treble, bass, state; 2143 2144 /* CHN_UNLOCK(c); */ 2145 treble = mix_get(m, SOUND_MIXER_TREBLE); 2146 bass = mix_get(m, SOUND_MIXER_BASS); 2147 /* CHN_LOCK(c); */ 2148 2149 if (treble == -1) 2150 treble = 50; 2151 else 2152 treble = ((treble & 0x7f) + 2153 ((treble >> 8) & 0x7f)) >> 1; 2154 2155 if (bass == -1) 2156 bass = 50; 2157 else 2158 bass = ((bass & 0x7f) + ((bass >> 8) & 0x7f)) >> 1; 2159 2160 f = chn_findfeeder(c, FEEDER_EQ); 2161 if (f != NULL) { 2162 if (FEEDER_SET(f, FEEDEQ_TREBLE, treble) != 0) 2163 device_printf(c->dev, 2164 "EQ: Failed to set treble -- %d\n", 2165 treble); 2166 if (FEEDER_SET(f, FEEDEQ_BASS, bass) != 0) 2167 device_printf(c->dev, 2168 "EQ: Failed to set bass -- %d\n", 2169 bass); 2170 if (FEEDER_SET(f, FEEDEQ_PREAMP, d->eqpreamp) != 0) 2171 device_printf(c->dev, 2172 "EQ: Failed to set preamp -- %d\n", 2173 d->eqpreamp); 2174 if (d->flags & SD_F_EQ_BYPASSED) 2175 state = FEEDEQ_BYPASS; 2176 else if (d->flags & SD_F_EQ_ENABLED) 2177 state = FEEDEQ_ENABLE; 2178 else 2179 state = FEEDEQ_DISABLE; 2180 if (FEEDER_SET(f, FEEDEQ_STATE, state) != 0) 2181 device_printf(c->dev, 2182 "EQ: Failed to set state -- %d\n", state); 2183 } 2184 } 2185 } 2186 2187 int 2188 chn_trigger(struct pcm_channel *c, int go) 2189 { 2190 struct snddev_info *d = c->parentsnddev; 2191 int ret; 2192 2193 CHN_LOCKASSERT(c); 2194 if (!PCMTRIG_COMMON(go)) 2195 return (CHANNEL_TRIGGER(c->methods, c->devinfo, go)); 2196 2197 if (go == c->trigger) 2198 return (0); 2199 2200 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go); 2201 if (ret != 0) 2202 return (ret); 2203 2204 switch (go) { 2205 case PCMTRIG_START: 2206 if (snd_verbose > 3) 2207 device_printf(c->dev, 2208 "%s() %s: calling go=0x%08x , " 2209 "prev=0x%08x\n", __func__, c->name, go, 2210 c->trigger); 2211 if (c->trigger != PCMTRIG_START) { 2212 c->trigger = go; 2213 CHN_UNLOCK(c); 2214 PCM_LOCK(d); 2215 CHN_INSERT_HEAD(d, c, channels.pcm.busy); 2216 PCM_UNLOCK(d); 2217 CHN_LOCK(c); 2218 chn_syncstate(c); 2219 } 2220 break; 2221 case PCMTRIG_STOP: 2222 case PCMTRIG_ABORT: 2223 if (snd_verbose > 3) 2224 device_printf(c->dev, 2225 "%s() %s: calling go=0x%08x , " 2226 "prev=0x%08x\n", __func__, c->name, go, 2227 c->trigger); 2228 if (c->trigger == PCMTRIG_START) { 2229 c->trigger = go; 2230 CHN_UNLOCK(c); 2231 PCM_LOCK(d); 2232 CHN_REMOVE(d, c, channels.pcm.busy); 2233 PCM_UNLOCK(d); 2234 CHN_LOCK(c); 2235 } 2236 break; 2237 default: 2238 break; 2239 } 2240 2241 return (0); 2242 } 2243 2244 /** 2245 * @brief Queries sound driver for sample-aligned hardware buffer pointer index 2246 * 2247 * This function obtains the hardware pointer location, then aligns it to 2248 * the current bytes-per-sample value before returning. (E.g., a channel 2249 * running in 16 bit stereo mode would require 4 bytes per sample, so a 2250 * hwptr value ranging from 32-35 would be returned as 32.) 2251 * 2252 * @param c PCM channel context 2253 * @returns sample-aligned hardware buffer pointer index 2254 */ 2255 int 2256 chn_getptr(struct pcm_channel *c) 2257 { 2258 int hwptr; 2259 2260 CHN_LOCKASSERT(c); 2261 hwptr = (CHN_STARTED(c)) ? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; 2262 return (hwptr - (hwptr % sndbuf_getalign(c->bufhard))); 2263 } 2264 2265 struct pcmchan_caps * 2266 chn_getcaps(struct pcm_channel *c) 2267 { 2268 CHN_LOCKASSERT(c); 2269 return CHANNEL_GETCAPS(c->methods, c->devinfo); 2270 } 2271 2272 u_int32_t 2273 chn_getformats(struct pcm_channel *c) 2274 { 2275 u_int32_t *fmtlist, fmts; 2276 int i; 2277 2278 fmtlist = chn_getcaps(c)->fmtlist; 2279 fmts = 0; 2280 for (i = 0; fmtlist[i]; i++) 2281 fmts |= fmtlist[i]; 2282 2283 /* report software-supported formats */ 2284 if (!CHN_BITPERFECT(c) && report_soft_formats) 2285 fmts |= AFMT_CONVERTIBLE; 2286 2287 return (AFMT_ENCODING(fmts)); 2288 } 2289 2290 int 2291 chn_notify(struct pcm_channel *c, u_int32_t flags) 2292 { 2293 struct pcm_channel *ch; 2294 struct pcmchan_caps *caps; 2295 uint32_t bestformat, bestspeed, besthwformat, *vchanformat, *vchanrate; 2296 uint32_t vpflags; 2297 int dirty, err, run, nrun; 2298 2299 CHN_LOCKASSERT(c); 2300 2301 if (CHN_EMPTY(c, children)) 2302 return (ENODEV); 2303 2304 err = 0; 2305 2306 /* 2307 * If the hwchan is running, we can't change its rate, format or 2308 * blocksize 2309 */ 2310 run = (CHN_STARTED(c)) ? 1 : 0; 2311 if (run) 2312 flags &= CHN_N_VOLUME | CHN_N_TRIGGER; 2313 2314 if (flags & CHN_N_RATE) { 2315 /* 2316 * XXX I'll make good use of this someday. 2317 * However this is currently being superseded by 2318 * the availability of CHN_F_VCHAN_DYNAMIC. 2319 */ 2320 } 2321 2322 if (flags & CHN_N_FORMAT) { 2323 /* 2324 * XXX I'll make good use of this someday. 2325 * However this is currently being superseded by 2326 * the availability of CHN_F_VCHAN_DYNAMIC. 2327 */ 2328 } 2329 2330 if (flags & CHN_N_VOLUME) { 2331 /* 2332 * XXX I'll make good use of this someday, though 2333 * soft volume control is currently pretty much 2334 * integrated. 2335 */ 2336 } 2337 2338 if (flags & CHN_N_BLOCKSIZE) { 2339 /* 2340 * Set to default latency profile 2341 */ 2342 chn_setlatency(c, chn_latency); 2343 } 2344 2345 if ((flags & CHN_N_TRIGGER) && !(c->flags & CHN_F_VCHAN_DYNAMIC)) { 2346 nrun = CHN_EMPTY(c, children.busy) ? 0 : 1; 2347 if (nrun && !run) 2348 err = chn_start(c, 1); 2349 if (!nrun && run) 2350 chn_abort(c); 2351 flags &= ~CHN_N_TRIGGER; 2352 } 2353 2354 if (flags & CHN_N_TRIGGER) { 2355 if (c->direction == PCMDIR_PLAY) { 2356 vchanformat = &c->parentsnddev->pvchanformat; 2357 vchanrate = &c->parentsnddev->pvchanrate; 2358 } else { 2359 vchanformat = &c->parentsnddev->rvchanformat; 2360 vchanrate = &c->parentsnddev->rvchanrate; 2361 } 2362 2363 /* Dynamic Virtual Channel */ 2364 if (!(c->flags & CHN_F_VCHAN_ADAPTIVE)) { 2365 bestformat = *vchanformat; 2366 bestspeed = *vchanrate; 2367 } else { 2368 bestformat = 0; 2369 bestspeed = 0; 2370 } 2371 2372 besthwformat = 0; 2373 nrun = 0; 2374 caps = chn_getcaps(c); 2375 dirty = 0; 2376 vpflags = 0; 2377 2378 CHN_FOREACH(ch, c, children.busy) { 2379 CHN_LOCK(ch); 2380 if ((ch->format & AFMT_PASSTHROUGH) && 2381 snd_fmtvalid(ch->format, caps->fmtlist)) { 2382 bestformat = ch->format; 2383 bestspeed = ch->speed; 2384 CHN_UNLOCK(ch); 2385 vpflags = CHN_F_PASSTHROUGH; 2386 nrun++; 2387 break; 2388 } 2389 if ((ch->flags & CHN_F_EXCLUSIVE) && vpflags == 0) { 2390 if (c->flags & CHN_F_VCHAN_ADAPTIVE) { 2391 bestspeed = ch->speed; 2392 RANGE(bestspeed, caps->minspeed, 2393 caps->maxspeed); 2394 besthwformat = snd_fmtbest(ch->format, 2395 caps->fmtlist); 2396 if (besthwformat != 0) 2397 bestformat = besthwformat; 2398 } 2399 CHN_UNLOCK(ch); 2400 vpflags = CHN_F_EXCLUSIVE; 2401 nrun++; 2402 continue; 2403 } 2404 if (!(c->flags & CHN_F_VCHAN_ADAPTIVE) || 2405 vpflags != 0) { 2406 CHN_UNLOCK(ch); 2407 nrun++; 2408 continue; 2409 } 2410 if (ch->speed > bestspeed) { 2411 bestspeed = ch->speed; 2412 RANGE(bestspeed, caps->minspeed, 2413 caps->maxspeed); 2414 } 2415 besthwformat = snd_fmtbest(ch->format, caps->fmtlist); 2416 if (!(besthwformat & AFMT_VCHAN)) { 2417 CHN_UNLOCK(ch); 2418 nrun++; 2419 continue; 2420 } 2421 if (AFMT_CHANNEL(besthwformat) > 2422 AFMT_CHANNEL(bestformat)) 2423 bestformat = besthwformat; 2424 else if (AFMT_CHANNEL(besthwformat) == 2425 AFMT_CHANNEL(bestformat) && 2426 AFMT_BIT(besthwformat) > AFMT_BIT(bestformat)) 2427 bestformat = besthwformat; 2428 CHN_UNLOCK(ch); 2429 nrun++; 2430 } 2431 2432 if (bestformat == 0) 2433 bestformat = c->format; 2434 if (bestspeed == 0) 2435 bestspeed = c->speed; 2436 2437 if (bestformat != c->format || bestspeed != c->speed) 2438 dirty = 1; 2439 2440 c->flags &= ~(CHN_F_PASSTHROUGH | CHN_F_EXCLUSIVE); 2441 c->flags |= vpflags; 2442 2443 if (nrun && !run) { 2444 if (dirty) { 2445 bestspeed = CHANNEL_SETSPEED(c->methods, 2446 c->devinfo, bestspeed); 2447 err = chn_reset(c, bestformat, bestspeed); 2448 } 2449 if (err == 0 && dirty) { 2450 CHN_FOREACH(ch, c, children.busy) { 2451 CHN_LOCK(ch); 2452 if (VCHAN_SYNC_REQUIRED(ch)) 2453 vchan_sync(ch); 2454 CHN_UNLOCK(ch); 2455 } 2456 } 2457 if (err == 0) { 2458 if (dirty) 2459 c->flags |= CHN_F_DIRTY; 2460 err = chn_start(c, 1); 2461 } 2462 } 2463 2464 if (nrun && run && dirty) { 2465 chn_abort(c); 2466 bestspeed = CHANNEL_SETSPEED(c->methods, c->devinfo, 2467 bestspeed); 2468 err = chn_reset(c, bestformat, bestspeed); 2469 if (err == 0) { 2470 CHN_FOREACH(ch, c, children.busy) { 2471 CHN_LOCK(ch); 2472 if (VCHAN_SYNC_REQUIRED(ch)) 2473 vchan_sync(ch); 2474 CHN_UNLOCK(ch); 2475 } 2476 } 2477 if (err == 0) { 2478 c->flags |= CHN_F_DIRTY; 2479 err = chn_start(c, 1); 2480 } 2481 } 2482 2483 if (err == 0 && !(bestformat & AFMT_PASSTHROUGH) && 2484 (bestformat & AFMT_VCHAN)) { 2485 *vchanformat = bestformat; 2486 *vchanrate = bestspeed; 2487 } 2488 2489 if (!nrun && run) { 2490 c->flags &= ~(CHN_F_PASSTHROUGH | CHN_F_EXCLUSIVE); 2491 bestformat = *vchanformat; 2492 bestspeed = *vchanrate; 2493 chn_abort(c); 2494 if (c->format != bestformat || c->speed != bestspeed) 2495 chn_reset(c, bestformat, bestspeed); 2496 } 2497 } 2498 2499 return (err); 2500 } 2501 2502 /** 2503 * @brief Fetch array of supported discrete sample rates 2504 * 2505 * Wrapper for CHANNEL_GETRATES. Please see channel_if.m:getrates() for 2506 * detailed information. 2507 * 2508 * @note If the operation isn't supported, this function will just return 0 2509 * (no rates in the array), and *rates will be set to NULL. Callers 2510 * should examine rates @b only if this function returns non-zero. 2511 * 2512 * @param c pcm channel to examine 2513 * @param rates pointer to array of integers; rate table will be recorded here 2514 * 2515 * @return number of rates in the array pointed to be @c rates 2516 */ 2517 int 2518 chn_getrates(struct pcm_channel *c, int **rates) 2519 { 2520 KASSERT(rates != NULL, ("rates is null")); 2521 CHN_LOCKASSERT(c); 2522 return CHANNEL_GETRATES(c->methods, c->devinfo, rates); 2523 } 2524 2525 /** 2526 * @brief Remove channel from a sync group, if there is one. 2527 * 2528 * This function is initially intended for the following conditions: 2529 * - Starting a syncgroup (@c SNDCTL_DSP_SYNCSTART ioctl) 2530 * - Closing a device. (A channel can't be destroyed if it's still in use.) 2531 * 2532 * @note Before calling this function, the syncgroup list mutex must be 2533 * held. (Consider pcm_channel::sm protected by the SG list mutex 2534 * whether @c c is locked or not.) 2535 * 2536 * @param c channel device to be started or closed 2537 * @returns If this channel was the only member of a group, the group ID 2538 * is returned to the caller so that the caller can release it 2539 * via free_unr() after giving up the syncgroup lock. Else it 2540 * returns 0. 2541 */ 2542 int 2543 chn_syncdestroy(struct pcm_channel *c) 2544 { 2545 struct pcmchan_syncmember *sm; 2546 struct pcmchan_syncgroup *sg; 2547 int sg_id; 2548 2549 sg_id = 0; 2550 2551 PCM_SG_LOCKASSERT(MA_OWNED); 2552 2553 if (c->sm != NULL) { 2554 sm = c->sm; 2555 sg = sm->parent; 2556 c->sm = NULL; 2557 2558 KASSERT(sg != NULL, ("syncmember has null parent")); 2559 2560 SLIST_REMOVE(&sg->members, sm, pcmchan_syncmember, link); 2561 free(sm, M_DEVBUF); 2562 2563 if (SLIST_EMPTY(&sg->members)) { 2564 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link); 2565 sg_id = sg->id; 2566 free(sg, M_DEVBUF); 2567 } 2568 } 2569 2570 return sg_id; 2571 } 2572 2573 #ifdef OSSV4_EXPERIMENT 2574 int 2575 chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak) 2576 { 2577 CHN_LOCKASSERT(c); 2578 return CHANNEL_GETPEAKS(c->methods, c->devinfo, lpeak, rpeak); 2579 } 2580 #endif 2581