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