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