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