1 /*- 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * Portions Copyright by Luigi Rizzo - 1997-99 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include "opt_isa.h" 29 30 #include <dev/sound/pcm/sound.h> 31 32 #include "feeder_if.h" 33 34 SND_DECLARE_FILE("$FreeBSD$"); 35 36 #define MIN_CHUNK_SIZE 256 /* for uiomove etc. */ 37 #if 0 38 #define DMA_ALIGN_THRESHOLD 4 39 #define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1)) 40 #endif 41 42 #define CANCHANGE(c) (!(c->flags & CHN_F_TRIGGERED)) 43 44 /* 45 #define DEB(x) x 46 */ 47 48 static int chn_targetirqrate = 32; 49 TUNABLE_INT("hw.snd.targetirqrate", &chn_targetirqrate); 50 51 static int 52 sysctl_hw_snd_targetirqrate(SYSCTL_HANDLER_ARGS) 53 { 54 int err, val; 55 56 val = chn_targetirqrate; 57 err = sysctl_handle_int(oidp, &val, sizeof(val), req); 58 if (val < 16 || val > 512) 59 err = EINVAL; 60 else 61 chn_targetirqrate = val; 62 63 return err; 64 } 65 SYSCTL_PROC(_hw_snd, OID_AUTO, targetirqrate, CTLTYPE_INT | CTLFLAG_RW, 66 0, sizeof(int), sysctl_hw_snd_targetirqrate, "I", ""); 67 static int report_soft_formats = 1; 68 SYSCTL_INT(_hw_snd, OID_AUTO, report_soft_formats, CTLFLAG_RW, 69 &report_soft_formats, 1, "report software-emulated formats"); 70 71 /** 72 * @brief Channel sync group lock 73 * 74 * Clients should acquire this lock @b without holding any channel locks 75 * before touching syncgroups or the main syncgroup list. 76 */ 77 struct mtx snd_pcm_syncgroups_mtx; 78 MTX_SYSINIT(pcm_syncgroup, &snd_pcm_syncgroups_mtx, "PCM channel sync group lock", MTX_DEF); 79 /** 80 * @brief syncgroups' master list 81 * 82 * Each time a channel syncgroup is created, it's added to this list. This 83 * list should only be accessed with @sa snd_pcm_syncgroups_mtx held. 84 * 85 * See SNDCTL_DSP_SYNCGROUP for more information. 86 */ 87 struct pcm_synclist snd_pcm_syncgroups = SLIST_HEAD_INITIALIZER(head); 88 89 static int chn_buildfeeder(struct pcm_channel *c); 90 91 static void 92 chn_lockinit(struct pcm_channel *c, int dir) 93 { 94 switch(dir) { 95 case PCMDIR_PLAY: 96 c->lock = snd_mtxcreate(c->name, "pcm play channel"); 97 break; 98 case PCMDIR_REC: 99 c->lock = snd_mtxcreate(c->name, "pcm record channel"); 100 break; 101 case PCMDIR_VIRTUAL: 102 c->lock = snd_mtxcreate(c->name, "pcm virtual play channel"); 103 break; 104 case 0: 105 c->lock = snd_mtxcreate(c->name, "pcm fake channel"); 106 break; 107 } 108 109 cv_init(&c->cv, c->name); 110 } 111 112 static void 113 chn_lockdestroy(struct pcm_channel *c) 114 { 115 snd_mtxfree(c->lock); 116 cv_destroy(&c->cv); 117 } 118 119 /** 120 * @brief Determine channel is ready for I/O 121 * 122 * @retval 1 = ready for I/O 123 * @retval 0 = not ready for I/O 124 */ 125 static int 126 chn_polltrigger(struct pcm_channel *c) 127 { 128 struct snd_dbuf *bs = c->bufsoft; 129 unsigned amt, lim; 130 131 CHN_LOCKASSERT(c); 132 if (c->flags & CHN_F_MAPPED) { 133 if (sndbuf_getprevblocks(bs) == 0) 134 return 1; 135 else 136 return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0; 137 } else { 138 amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs); 139 #if 0 140 lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1; 141 #endif 142 lim = c->lw; 143 return (amt >= lim) ? 1 : 0; 144 } 145 return 0; 146 } 147 148 static int 149 chn_pollreset(struct pcm_channel *c) 150 { 151 struct snd_dbuf *bs = c->bufsoft; 152 153 CHN_LOCKASSERT(c); 154 sndbuf_updateprevtotal(bs); 155 return 1; 156 } 157 158 static void 159 chn_wakeup(struct pcm_channel *c) 160 { 161 struct snd_dbuf *bs = c->bufsoft; 162 struct pcmchan_children *pce; 163 164 CHN_LOCKASSERT(c); 165 if (SLIST_EMPTY(&c->children)) { 166 if (SEL_WAITING(sndbuf_getsel(bs)) && chn_polltrigger(c)) 167 selwakeuppri(sndbuf_getsel(bs), PRIBIO); 168 } else { 169 SLIST_FOREACH(pce, &c->children, link) { 170 CHN_LOCK(pce->channel); 171 chn_wakeup(pce->channel); 172 CHN_UNLOCK(pce->channel); 173 } 174 } 175 176 wakeup(bs); 177 } 178 179 static int 180 chn_sleep(struct pcm_channel *c, char *str, int timeout) 181 { 182 struct snd_dbuf *bs = c->bufsoft; 183 int ret; 184 185 CHN_LOCKASSERT(c); 186 #ifdef USING_MUTEX 187 ret = msleep(bs, c->lock, PRIBIO | PCATCH, str, timeout); 188 #else 189 ret = tsleep(bs, PRIBIO | PCATCH, str, timeout); 190 #endif 191 192 return ret; 193 } 194 195 /* 196 * chn_dmaupdate() tracks the status of a dma transfer, 197 * updating pointers. 198 */ 199 200 static unsigned int 201 chn_dmaupdate(struct pcm_channel *c) 202 { 203 struct snd_dbuf *b = c->bufhard; 204 unsigned int delta, old, hwptr, amt; 205 206 KASSERT(sndbuf_getsize(b) > 0, ("bufsize == 0")); 207 CHN_LOCKASSERT(c); 208 209 old = sndbuf_gethwptr(b); 210 hwptr = chn_getptr(c); 211 delta = (sndbuf_getsize(b) + hwptr - old) % sndbuf_getsize(b); 212 sndbuf_sethwptr(b, hwptr); 213 214 DEB( 215 if (delta >= ((sndbuf_getsize(b) * 15) / 16)) { 216 if (!(c->flags & (CHN_F_CLOSING | CHN_F_ABORTING))) 217 device_printf(c->dev, "hwptr went backwards %d -> %d\n", old, hwptr); 218 } 219 ); 220 221 if (c->direction == PCMDIR_PLAY) { 222 amt = MIN(delta, sndbuf_getready(b)); 223 if (amt > 0) 224 sndbuf_dispose(b, NULL, amt); 225 } else { 226 amt = MIN(delta, sndbuf_getfree(b)); 227 if (amt > 0) 228 sndbuf_acquire(b, NULL, amt); 229 } 230 231 return delta; 232 } 233 234 void 235 chn_wrupdate(struct pcm_channel *c) 236 { 237 int ret; 238 239 CHN_LOCKASSERT(c); 240 KASSERT(c->direction == PCMDIR_PLAY, ("chn_wrupdate on bad channel")); 241 242 if ((c->flags & (CHN_F_MAPPED | CHN_F_VIRTUAL)) || !(c->flags & CHN_F_TRIGGERED)) 243 return; 244 chn_dmaupdate(c); 245 ret = chn_wrfeed(c); 246 /* tell the driver we've updated the primary buffer */ 247 chn_trigger(c, PCMTRIG_EMLDMAWR); 248 DEB(if (ret) 249 printf("chn_wrupdate: chn_wrfeed returned %d\n", ret);) 250 251 } 252 253 int 254 chn_wrfeed(struct pcm_channel *c) 255 { 256 struct snd_dbuf *b = c->bufhard; 257 struct snd_dbuf *bs = c->bufsoft; 258 unsigned int ret, amt; 259 260 CHN_LOCKASSERT(c); 261 #if 0 262 DEB( 263 if (c->flags & CHN_F_CLOSING) { 264 sndbuf_dump(b, "b", 0x02); 265 sndbuf_dump(bs, "bs", 0x02); 266 }) 267 #endif 268 269 if (c->flags & CHN_F_MAPPED) 270 sndbuf_acquire(bs, NULL, sndbuf_getfree(bs)); 271 272 amt = sndbuf_getfree(b); 273 KASSERT(amt <= sndbuf_getsize(bs), 274 ("%s(%s): amt %d > source size %d, flags 0x%x", __func__, c->name, 275 amt, sndbuf_getsize(bs), c->flags)); 276 277 ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC; 278 /* 279 * Possible xruns. There should be no empty space left in buffer. 280 */ 281 if (sndbuf_getfree(b) > 0) 282 c->xruns++; 283 284 if (ret == 0 && sndbuf_getfree(b) < amt) 285 chn_wakeup(c); 286 287 return ret; 288 } 289 290 static void 291 chn_wrintr(struct pcm_channel *c) 292 { 293 int ret; 294 295 CHN_LOCKASSERT(c); 296 /* update pointers in primary buffer */ 297 chn_dmaupdate(c); 298 /* ...and feed from secondary to primary */ 299 ret = chn_wrfeed(c); 300 /* tell the driver we've updated the primary buffer */ 301 chn_trigger(c, PCMTRIG_EMLDMAWR); 302 DEB(if (ret) 303 printf("chn_wrintr: chn_wrfeed returned %d\n", ret);) 304 } 305 306 /* 307 * user write routine - uiomove data into secondary buffer, trigger if necessary 308 * if blocking, sleep, rinse and repeat. 309 * 310 * called externally, so must handle locking 311 */ 312 313 int 314 chn_write(struct pcm_channel *c, struct uio *buf) 315 { 316 int ret, timeout, newsize, count, sz; 317 struct snd_dbuf *bs = c->bufsoft; 318 void *off; 319 int t, x,togo,p; 320 321 CHN_LOCKASSERT(c); 322 /* 323 * XXX Certain applications attempt to write larger size 324 * of pcm data than c->blocksize2nd without blocking, 325 * resulting partial write. Expand the block size so that 326 * the write operation avoids blocking. 327 */ 328 if ((c->flags & CHN_F_NBIO) && buf->uio_resid > sndbuf_getblksz(bs)) { 329 DEB(device_printf(c->dev, "broken app, nbio and tried to write %d bytes with fragsz %d\n", 330 buf->uio_resid, sndbuf_getblksz(bs))); 331 newsize = 16; 332 while (newsize < min(buf->uio_resid, CHN_2NDBUFMAXSIZE / 2)) 333 newsize <<= 1; 334 chn_setblocksize(c, sndbuf_getblkcnt(bs), newsize); 335 DEB(device_printf(c->dev, "frags reset to %d x %d\n", sndbuf_getblkcnt(bs), sndbuf_getblksz(bs))); 336 } 337 338 ret = 0; 339 count = hz; 340 341 while (!ret && (buf->uio_resid > 0) && (count > 0)) { 342 sz = sndbuf_getfree(bs); 343 if (sz == 0) { 344 if (c->flags & CHN_F_NBIO) 345 ret = EWOULDBLOCK; 346 else if (c->flags & CHN_F_NOTRIGGER) { 347 /** 348 * @todo Evaluate whether EAGAIN is truly desirable. 349 * 4Front drivers behave like this, but I'm 350 * not sure if it at all violates the "write 351 * should be allowed to block" model. 352 * 353 * The idea is that, while set with CHN_F_NOTRIGGER, 354 * a channel isn't playing, *but* without this we 355 * end up with "interrupt timeout / channel dead". 356 */ 357 ret = EAGAIN; 358 } else { 359 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); 360 if (timeout < 1) 361 timeout = 1; 362 timeout = 1; 363 ret = chn_sleep(c, "pcmwr", timeout); 364 if (ret == EWOULDBLOCK) { 365 count -= timeout; 366 ret = 0; 367 } else if (ret == 0) 368 count = hz; 369 } 370 } else { 371 sz = MIN(sz, buf->uio_resid); 372 KASSERT(sz > 0, ("confusion in chn_write")); 373 /* printf("sz: %d\n", sz); */ 374 375 /* 376 * The following assumes that the free space in 377 * the buffer can never be less around the 378 * unlock-uiomove-lock sequence. 379 */ 380 togo = sz; 381 while (ret == 0 && togo> 0) { 382 p = sndbuf_getfreeptr(bs); 383 t = MIN(togo, sndbuf_getsize(bs) - p); 384 off = sndbuf_getbufofs(bs, p); 385 CHN_UNLOCK(c); 386 ret = uiomove(off, t, buf); 387 CHN_LOCK(c); 388 togo -= t; 389 x = sndbuf_acquire(bs, NULL, t); 390 } 391 ret = 0; 392 if (ret == 0 && !(c->flags & CHN_F_TRIGGERED)) 393 chn_start(c, 0); 394 } 395 } 396 /* printf("ret: %d left: %d\n", ret, buf->uio_resid); */ 397 398 if (count <= 0) { 399 c->flags |= CHN_F_DEAD; 400 printf("%s: play interrupt timeout, channel dead\n", c->name); 401 } 402 403 return ret; 404 } 405 406 #if 0 407 static int 408 chn_rddump(struct pcm_channel *c, unsigned int cnt) 409 { 410 struct snd_dbuf *b = c->bufhard; 411 412 CHN_LOCKASSERT(c); 413 #if 0 414 static uint32_t kk = 0; 415 printf("%u: dumping %d bytes\n", ++kk, cnt); 416 #endif 417 c->xruns++; 418 sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt); 419 return sndbuf_dispose(b, NULL, cnt); 420 } 421 #endif 422 423 /* 424 * Feed new data from the read buffer. Can be called in the bottom half. 425 */ 426 int 427 chn_rdfeed(struct pcm_channel *c) 428 { 429 struct snd_dbuf *b = c->bufhard; 430 struct snd_dbuf *bs = c->bufsoft; 431 unsigned int ret, amt; 432 433 CHN_LOCKASSERT(c); 434 DEB( 435 if (c->flags & CHN_F_CLOSING) { 436 sndbuf_dump(b, "b", 0x02); 437 sndbuf_dump(bs, "bs", 0x02); 438 }) 439 440 #if 0 441 amt = sndbuf_getready(b); 442 if (sndbuf_getfree(bs) < amt) { 443 c->xruns++; 444 amt = sndbuf_getfree(bs); 445 } 446 #endif 447 amt = sndbuf_getfree(bs); 448 ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0; 449 450 amt = sndbuf_getready(b); 451 if (amt > 0) { 452 c->xruns++; 453 sndbuf_dispose(b, NULL, amt); 454 } 455 456 chn_wakeup(c); 457 458 return ret; 459 } 460 461 void 462 chn_rdupdate(struct pcm_channel *c) 463 { 464 int ret; 465 466 CHN_LOCKASSERT(c); 467 KASSERT(c->direction == PCMDIR_REC, ("chn_rdupdate on bad channel")); 468 469 if ((c->flags & CHN_F_MAPPED) || !(c->flags & CHN_F_TRIGGERED)) 470 return; 471 chn_trigger(c, PCMTRIG_EMLDMARD); 472 chn_dmaupdate(c); 473 ret = chn_rdfeed(c); 474 DEB(if (ret) 475 printf("chn_rdfeed: %d\n", ret);) 476 477 } 478 479 /* read interrupt routine. Must be called with interrupts blocked. */ 480 static void 481 chn_rdintr(struct pcm_channel *c) 482 { 483 int ret; 484 485 CHN_LOCKASSERT(c); 486 /* tell the driver to update the primary buffer if non-dma */ 487 chn_trigger(c, PCMTRIG_EMLDMARD); 488 /* update pointers in primary buffer */ 489 chn_dmaupdate(c); 490 /* ...and feed from primary to secondary */ 491 ret = chn_rdfeed(c); 492 } 493 494 /* 495 * user read routine - trigger if necessary, uiomove data from secondary buffer 496 * if blocking, sleep, rinse and repeat. 497 * 498 * called externally, so must handle locking 499 */ 500 501 int 502 chn_read(struct pcm_channel *c, struct uio *buf) 503 { 504 int ret, timeout, sz, count; 505 struct snd_dbuf *bs = c->bufsoft; 506 void *off; 507 int t, x,togo,p; 508 509 CHN_LOCKASSERT(c); 510 if (!(c->flags & CHN_F_TRIGGERED)) 511 chn_start(c, 0); 512 513 ret = 0; 514 count = hz; 515 while (!ret && (buf->uio_resid > 0) && (count > 0)) { 516 sz = MIN(buf->uio_resid, sndbuf_getready(bs)); 517 518 if (sz > 0) { 519 /* 520 * The following assumes that the free space in 521 * the buffer can never be less around the 522 * unlock-uiomove-lock sequence. 523 */ 524 togo = sz; 525 while (ret == 0 && togo> 0) { 526 p = sndbuf_getreadyptr(bs); 527 t = MIN(togo, sndbuf_getsize(bs) - p); 528 off = sndbuf_getbufofs(bs, p); 529 CHN_UNLOCK(c); 530 ret = uiomove(off, t, buf); 531 CHN_LOCK(c); 532 togo -= t; 533 x = sndbuf_dispose(bs, NULL, t); 534 } 535 ret = 0; 536 } else { 537 if (c->flags & CHN_F_NBIO) { 538 ret = EWOULDBLOCK; 539 } else { 540 timeout = (hz * sndbuf_getblksz(bs)) / (sndbuf_getspd(bs) * sndbuf_getbps(bs)); 541 if (timeout < 1) 542 timeout = 1; 543 ret = chn_sleep(c, "pcmrd", timeout); 544 if (ret == EWOULDBLOCK) { 545 count -= timeout; 546 ret = 0; 547 } else { 548 count = hz; 549 } 550 551 } 552 } 553 } 554 555 if (count <= 0) { 556 c->flags |= CHN_F_DEAD; 557 printf("%s: record interrupt timeout, channel dead\n", c->name); 558 } 559 560 return ret; 561 } 562 563 void 564 chn_intr(struct pcm_channel *c) 565 { 566 CHN_LOCK(c); 567 c->interrupts++; 568 if (c->direction == PCMDIR_PLAY) 569 chn_wrintr(c); 570 else 571 chn_rdintr(c); 572 CHN_UNLOCK(c); 573 } 574 575 u_int32_t 576 chn_start(struct pcm_channel *c, int force) 577 { 578 u_int32_t i, j; 579 struct snd_dbuf *b = c->bufhard; 580 struct snd_dbuf *bs = c->bufsoft; 581 582 CHN_LOCKASSERT(c); 583 /* if we're running, or if we're prevented from triggering, bail */ 584 if ((c->flags & CHN_F_TRIGGERED) || ((c->flags & CHN_F_NOTRIGGER) && !force)) 585 return EINVAL; 586 587 i = (c->direction == PCMDIR_PLAY)? sndbuf_getready(bs) : sndbuf_getfree(bs); 588 j = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(b) : sndbuf_getready(b); 589 if (force || (i >= j)) { 590 c->flags |= CHN_F_TRIGGERED; 591 /* 592 * if we're starting because a vchan started, don't feed any data 593 * or it becomes impossible to start vchans synchronised with the 594 * first one. the hardbuf should be empty so we top it up with 595 * silence to give it something to chew. the real data will be 596 * fed at the first irq. 597 */ 598 if (c->direction == PCMDIR_PLAY) { 599 /* 600 * Reduce pops during playback startup. 601 */ 602 sndbuf_fillsilence(b); 603 if (SLIST_EMPTY(&c->children)) 604 chn_wrfeed(c); 605 } 606 sndbuf_setrun(b, 1); 607 c->xruns = 0; 608 chn_trigger(c, PCMTRIG_START); 609 return 0; 610 } 611 612 return 0; 613 } 614 615 void 616 chn_resetbuf(struct pcm_channel *c) 617 { 618 struct snd_dbuf *b = c->bufhard; 619 struct snd_dbuf *bs = c->bufsoft; 620 621 c->blocks = 0; 622 sndbuf_reset(b); 623 sndbuf_reset(bs); 624 } 625 626 /* 627 * chn_sync waits until the space in the given channel goes above 628 * a threshold. The threshold is checked against fl or rl respectively. 629 * Assume that the condition can become true, do not check here... 630 */ 631 int 632 chn_sync(struct pcm_channel *c, int threshold) 633 { 634 u_long rdy; 635 int ret; 636 struct snd_dbuf *bs = c->bufsoft; 637 638 CHN_LOCKASSERT(c); 639 640 /* if we haven't yet started and nothing is buffered, else start*/ 641 if (!(c->flags & CHN_F_TRIGGERED)) { 642 if (sndbuf_getready(bs) > 0) { 643 ret = chn_start(c, 1); 644 if (ret) 645 return ret; 646 } else { 647 return 0; 648 } 649 } 650 651 for (;;) { 652 rdy = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs); 653 if (rdy <= threshold) { 654 ret = chn_sleep(c, "pcmsyn", 1); 655 if (ret == ERESTART || ret == EINTR) { 656 DEB(printf("chn_sync: tsleep returns %d\n", ret)); 657 return -1; 658 } 659 } else 660 break; 661 } 662 return 0; 663 } 664 665 /* called externally, handle locking */ 666 int 667 chn_poll(struct pcm_channel *c, int ev, struct thread *td) 668 { 669 struct snd_dbuf *bs = c->bufsoft; 670 int ret; 671 672 CHN_LOCKASSERT(c); 673 if (!(c->flags & CHN_F_MAPPED) && !(c->flags & CHN_F_TRIGGERED)) 674 chn_start(c, 1); 675 ret = 0; 676 if (chn_polltrigger(c) && chn_pollreset(c)) 677 ret = ev; 678 else 679 selrecord(td, sndbuf_getsel(bs)); 680 return ret; 681 } 682 683 /* 684 * chn_abort terminates a running dma transfer. it may sleep up to 200ms. 685 * it returns the number of bytes that have not been transferred. 686 * 687 * called from: dsp_close, dsp_ioctl, with channel locked 688 */ 689 int 690 chn_abort(struct pcm_channel *c) 691 { 692 int missing = 0; 693 struct snd_dbuf *b = c->bufhard; 694 struct snd_dbuf *bs = c->bufsoft; 695 696 CHN_LOCKASSERT(c); 697 if (!(c->flags & CHN_F_TRIGGERED)) 698 return 0; 699 c->flags |= CHN_F_ABORTING; 700 701 c->flags &= ~CHN_F_TRIGGERED; 702 /* kill the channel */ 703 chn_trigger(c, PCMTRIG_ABORT); 704 sndbuf_setrun(b, 0); 705 if (!(c->flags & CHN_F_VIRTUAL)) 706 chn_dmaupdate(c); 707 missing = sndbuf_getready(bs) + sndbuf_getready(b); 708 709 c->flags &= ~CHN_F_ABORTING; 710 return missing; 711 } 712 713 /* 714 * this routine tries to flush the dma transfer. It is called 715 * on a close of a playback channel. 716 * first, if there is data in the buffer, but the dma has not yet 717 * begun, we need to start it. 718 * next, we wait for the play buffer to drain 719 * finally, we stop the dma. 720 * 721 * called from: dsp_close, not valid for record channels. 722 */ 723 724 int 725 chn_flush(struct pcm_channel *c) 726 { 727 int ret, count, resid, resid_p; 728 struct snd_dbuf *b = c->bufhard; 729 struct snd_dbuf *bs = c->bufsoft; 730 731 CHN_LOCKASSERT(c); 732 KASSERT(c->direction == PCMDIR_PLAY, ("chn_flush on bad channel")); 733 DEB(printf("chn_flush: c->flags 0x%08x\n", c->flags)); 734 735 /* if we haven't yet started and nothing is buffered, else start*/ 736 if (!(c->flags & CHN_F_TRIGGERED)) { 737 if (sndbuf_getready(bs) > 0) { 738 ret = chn_start(c, 1); 739 if (ret) 740 return ret; 741 } else { 742 return 0; 743 } 744 } 745 746 c->flags |= CHN_F_CLOSING; 747 resid = sndbuf_getready(bs) + sndbuf_getready(b); 748 resid_p = resid; 749 count = 10; 750 ret = 0; 751 while ((count > 0) && (resid > sndbuf_getsize(b)) && (ret == 0)) { 752 /* still pending output data. */ 753 ret = chn_sleep(c, "pcmflu", hz / 10); 754 if (ret == EWOULDBLOCK) 755 ret = 0; 756 if (ret == 0) { 757 resid = sndbuf_getready(bs) + sndbuf_getready(b); 758 if (resid == resid_p) 759 count--; 760 if (resid > resid_p) 761 DEB(printf("chn_flush: buffer length increasind %d -> %d\n", resid_p, resid)); 762 resid_p = resid; 763 } 764 } 765 if (count == 0) 766 DEB(printf("chn_flush: timeout, hw %d, sw %d\n", 767 sndbuf_getready(b), sndbuf_getready(bs))); 768 769 c->flags &= ~CHN_F_TRIGGERED; 770 /* kill the channel */ 771 chn_trigger(c, PCMTRIG_ABORT); 772 sndbuf_setrun(b, 0); 773 774 c->flags &= ~CHN_F_CLOSING; 775 return 0; 776 } 777 778 int 779 fmtvalid(u_int32_t fmt, u_int32_t *fmtlist) 780 { 781 int i; 782 783 for (i = 0; fmtlist[i]; i++) 784 if (fmt == fmtlist[i]) 785 return 1; 786 return 0; 787 } 788 789 int 790 chn_reset(struct pcm_channel *c, u_int32_t fmt) 791 { 792 int hwspd, r; 793 794 CHN_LOCKASSERT(c); 795 c->flags &= CHN_F_RESET; 796 c->interrupts = 0; 797 c->xruns = 0; 798 799 r = CHANNEL_RESET(c->methods, c->devinfo); 800 if (fmt != 0) { 801 #if 0 802 hwspd = DSP_DEFAULT_SPEED; 803 /* only do this on a record channel until feederbuilder works */ 804 if (c->direction == PCMDIR_REC) 805 RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 806 c->speed = hwspd; 807 #endif 808 hwspd = chn_getcaps(c)->minspeed; 809 c->speed = hwspd; 810 811 if (r == 0) 812 r = chn_setformat(c, fmt); 813 if (r == 0) 814 r = chn_setspeed(c, hwspd); 815 #if 0 816 if (r == 0) 817 r = chn_setvolume(c, 100, 100); 818 #endif 819 } 820 if (r == 0) 821 r = chn_setblocksize(c, 0, 0); 822 if (r == 0) { 823 chn_resetbuf(c); 824 r = CHANNEL_RESETDONE(c->methods, c->devinfo); 825 } 826 return r; 827 } 828 829 int 830 chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction) 831 { 832 struct feeder_class *fc; 833 struct snd_dbuf *b, *bs; 834 int ret; 835 836 chn_lockinit(c, dir); 837 838 b = NULL; 839 bs = NULL; 840 c->devinfo = NULL; 841 c->feeder = NULL; 842 843 ret = ENOMEM; 844 b = sndbuf_create(c->dev, c->name, "primary", c); 845 if (b == NULL) 846 goto out; 847 bs = sndbuf_create(c->dev, c->name, "secondary", c); 848 if (bs == NULL) 849 goto out; 850 851 CHN_LOCK(c); 852 853 ret = EINVAL; 854 fc = feeder_getclass(NULL); 855 if (fc == NULL) 856 goto out; 857 if (chn_addfeeder(c, fc, NULL)) 858 goto out; 859 860 /* 861 * XXX - sndbuf_setup() & sndbuf_resize() expect to be called 862 * with the channel unlocked because they are also called 863 * from driver methods that don't know about locking 864 */ 865 CHN_UNLOCK(c); 866 sndbuf_setup(bs, NULL, 0); 867 CHN_LOCK(c); 868 c->bufhard = b; 869 c->bufsoft = bs; 870 c->flags = 0; 871 c->feederflags = 0; 872 c->sm = NULL; 873 874 ret = ENODEV; 875 CHN_UNLOCK(c); /* XXX - Unlock for CHANNEL_INIT() malloc() call */ 876 c->devinfo = CHANNEL_INIT(c->methods, devinfo, b, c, direction); 877 CHN_LOCK(c); 878 if (c->devinfo == NULL) 879 goto out; 880 881 ret = ENOMEM; 882 if ((sndbuf_getsize(b) == 0) && ((c->flags & CHN_F_VIRTUAL) == 0)) 883 goto out; 884 885 ret = chn_setdir(c, direction); 886 if (ret) 887 goto out; 888 889 ret = sndbuf_setfmt(b, AFMT_U8); 890 if (ret) 891 goto out; 892 893 ret = sndbuf_setfmt(bs, AFMT_U8); 894 if (ret) 895 goto out; 896 897 /** 898 * @todo Should this be moved somewhere else? The primary buffer 899 * is allocated by the driver or via DMA map setup, and tmpbuf 900 * seems to only come into existence in sndbuf_resize(). 901 */ 902 if (c->direction == PCMDIR_PLAY) { 903 bs->sl = sndbuf_getmaxsize(bs); 904 bs->shadbuf = malloc(bs->sl, M_DEVBUF, M_NOWAIT); 905 if (bs->shadbuf == NULL) { 906 ret = ENOMEM; 907 goto out; 908 } 909 } 910 911 out: 912 CHN_UNLOCK(c); 913 if (ret) { 914 if (c->devinfo) { 915 if (CHANNEL_FREE(c->methods, c->devinfo)) 916 sndbuf_free(b); 917 } 918 if (bs) 919 sndbuf_destroy(bs); 920 if (b) 921 sndbuf_destroy(b); 922 c->flags |= CHN_F_DEAD; 923 chn_lockdestroy(c); 924 925 return ret; 926 } 927 928 return 0; 929 } 930 931 int 932 chn_kill(struct pcm_channel *c) 933 { 934 struct snd_dbuf *b = c->bufhard; 935 struct snd_dbuf *bs = c->bufsoft; 936 937 if (c->flags & CHN_F_TRIGGERED) 938 chn_trigger(c, PCMTRIG_ABORT); 939 while (chn_removefeeder(c) == 0); 940 if (CHANNEL_FREE(c->methods, c->devinfo)) 941 sndbuf_free(b); 942 c->flags |= CHN_F_DEAD; 943 sndbuf_destroy(bs); 944 sndbuf_destroy(b); 945 chn_lockdestroy(c); 946 return 0; 947 } 948 949 int 950 chn_setdir(struct pcm_channel *c, int dir) 951 { 952 #ifdef DEV_ISA 953 struct snd_dbuf *b = c->bufhard; 954 #endif 955 int r; 956 957 CHN_LOCKASSERT(c); 958 c->direction = dir; 959 r = CHANNEL_SETDIR(c->methods, c->devinfo, c->direction); 960 #ifdef DEV_ISA 961 if (!r && SND_DMA(b)) 962 sndbuf_dmasetdir(b, c->direction); 963 #endif 964 return r; 965 } 966 967 int 968 chn_setvolume(struct pcm_channel *c, int left, int right) 969 { 970 CHN_LOCKASSERT(c); 971 /* should add a feeder for volume changing if channel returns -1 */ 972 if (left > 100) 973 left = 100; 974 if (left < 0) 975 left = 0; 976 if (right > 100) 977 right = 100; 978 if (right < 0) 979 right = 0; 980 c->volume = left | (right << 8); 981 return 0; 982 } 983 984 static int 985 chn_tryspeed(struct pcm_channel *c, int speed) 986 { 987 struct pcm_feeder *f; 988 struct snd_dbuf *b = c->bufhard; 989 struct snd_dbuf *bs = c->bufsoft; 990 struct snd_dbuf *x; 991 int r, delta; 992 993 CHN_LOCKASSERT(c); 994 DEB(printf("setspeed, channel %s\n", c->name)); 995 DEB(printf("want speed %d, ", speed)); 996 if (speed <= 0) 997 return EINVAL; 998 if (CANCHANGE(c)) { 999 r = 0; 1000 c->speed = speed; 1001 sndbuf_setspd(bs, speed); 1002 RANGE(speed, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed); 1003 DEB(printf("try speed %d, ", speed)); 1004 sndbuf_setspd(b, CHANNEL_SETSPEED(c->methods, c->devinfo, speed)); 1005 DEB(printf("got speed %d\n", sndbuf_getspd(b))); 1006 1007 delta = sndbuf_getspd(b) - sndbuf_getspd(bs); 1008 if (delta < 0) 1009 delta = -delta; 1010 1011 c->feederflags &= ~(1 << FEEDER_RATE); 1012 /* 1013 * Used to be 500. It was too big! 1014 */ 1015 if (delta > 25) 1016 c->feederflags |= 1 << FEEDER_RATE; 1017 else 1018 sndbuf_setspd(bs, sndbuf_getspd(b)); 1019 1020 r = chn_buildfeeder(c); 1021 DEB(printf("r = %d\n", r)); 1022 if (r) 1023 goto out; 1024 1025 r = chn_setblocksize(c, 0, 0); 1026 if (r) 1027 goto out; 1028 1029 if (!(c->feederflags & (1 << FEEDER_RATE))) 1030 goto out; 1031 1032 r = EINVAL; 1033 f = chn_findfeeder(c, FEEDER_RATE); 1034 DEB(printf("feedrate = %p\n", f)); 1035 if (f == NULL) 1036 goto out; 1037 1038 x = (c->direction == PCMDIR_REC)? b : bs; 1039 r = FEEDER_SET(f, FEEDRATE_SRC, sndbuf_getspd(x)); 1040 DEB(printf("feeder_set(FEEDRATE_SRC, %d) = %d\n", sndbuf_getspd(x), r)); 1041 if (r) 1042 goto out; 1043 1044 x = (c->direction == PCMDIR_REC)? bs : b; 1045 r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x)); 1046 DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r)); 1047 out: 1048 if (!r) 1049 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, 1050 sndbuf_getfmt(b)); 1051 if (!r) 1052 sndbuf_setfmt(bs, c->format); 1053 DEB(printf("setspeed done, r = %d\n", r)); 1054 return r; 1055 } else 1056 return EINVAL; 1057 } 1058 1059 int 1060 chn_setspeed(struct pcm_channel *c, int speed) 1061 { 1062 int r, oldspeed = c->speed; 1063 1064 r = chn_tryspeed(c, speed); 1065 if (r) { 1066 DEB(printf("Failed to set speed %d falling back to %d\n", speed, oldspeed)); 1067 r = chn_tryspeed(c, oldspeed); 1068 } 1069 return r; 1070 } 1071 1072 static int 1073 chn_tryformat(struct pcm_channel *c, u_int32_t fmt) 1074 { 1075 struct snd_dbuf *b = c->bufhard; 1076 struct snd_dbuf *bs = c->bufsoft; 1077 int r; 1078 1079 CHN_LOCKASSERT(c); 1080 if (CANCHANGE(c)) { 1081 DEB(printf("want format %d\n", fmt)); 1082 c->format = fmt; 1083 r = chn_buildfeeder(c); 1084 if (r == 0) { 1085 sndbuf_setfmt(bs, c->format); 1086 chn_resetbuf(c); 1087 r = CHANNEL_SETFORMAT(c->methods, c->devinfo, sndbuf_getfmt(b)); 1088 if (r == 0) 1089 r = chn_tryspeed(c, c->speed); 1090 } 1091 return r; 1092 } else 1093 return EINVAL; 1094 } 1095 1096 int 1097 chn_setformat(struct pcm_channel *c, u_int32_t fmt) 1098 { 1099 u_int32_t oldfmt = c->format; 1100 int r; 1101 1102 r = chn_tryformat(c, fmt); 1103 if (r) { 1104 DEB(printf("Format change %d failed, reverting to %d\n", fmt, oldfmt)); 1105 chn_tryformat(c, oldfmt); 1106 } 1107 return r; 1108 } 1109 1110 /* 1111 * given a bufsz value, round it to a power of 2 in the min-max range 1112 * XXX only works if min and max are powers of 2 1113 */ 1114 static int 1115 round_bufsz(int bufsz, int min, int max) 1116 { 1117 int tmp = min * 2; 1118 1119 KASSERT((min & (min-1)) == 0, ("min %d must be power of 2\n", min)); 1120 KASSERT((max & (max-1)) == 0, ("max %d must be power of 2\n", max)); 1121 while (tmp <= bufsz) 1122 tmp <<= 1; 1123 tmp >>= 1; 1124 if (tmp > max) 1125 tmp = max; 1126 return tmp; 1127 } 1128 1129 /* 1130 * set the channel's blocksize both for soft and hard buffers. 1131 * 1132 * blksz should be a power of 2 between 2**4 and 2**16 -- it is useful 1133 * that it has the same value for both bufsoft and bufhard. 1134 * blksz == -1 computes values according to a target irq rate. 1135 * blksz == 0 reuses previous values if available, otherwise 1136 * behaves as for -1 1137 * 1138 * blkcnt is set by the user, between 2 and (2**17)/blksz for bufsoft, 1139 * but should be a power of 2 for bufhard to simplify life to low 1140 * level drivers. 1141 * Note, for the rec channel a large blkcnt is ok, 1142 * but for the play channel we want blksz as small as possible to keep 1143 * the delay small, because routines in the write path always try to 1144 * keep bufhard full. 1145 * 1146 * Unless we have good reason to, use the values suggested by the caller. 1147 */ 1148 int 1149 chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz) 1150 { 1151 struct snd_dbuf *b = c->bufhard; 1152 struct snd_dbuf *bs = c->bufsoft; 1153 int irqhz, ret, maxsz, maxsize, reqblksz; 1154 1155 CHN_LOCKASSERT(c); 1156 if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) { 1157 KASSERT(sndbuf_getsize(bs) == 0 || 1158 sndbuf_getsize(bs) >= sndbuf_getsize(b), 1159 ("%s(%s): bufsoft size %d < bufhard size %d", __func__, 1160 c->name, sndbuf_getsize(bs), sndbuf_getsize(b))); 1161 return EINVAL; 1162 } 1163 c->flags |= CHN_F_SETBLOCKSIZE; 1164 1165 ret = 0; 1166 DEB(printf("%s(%d, %d)\n", __func__, blkcnt, blksz)); 1167 if (blksz == 0 || blksz == -1) { /* let the driver choose values */ 1168 if (blksz == -1) /* delete previous values */ 1169 c->flags &= ~CHN_F_HAS_SIZE; 1170 if (!(c->flags & CHN_F_HAS_SIZE)) { /* no previous value */ 1171 /* 1172 * compute a base blksz according to the target irq 1173 * rate, then round to a suitable power of 2 1174 * in the range 16.. 2^17/2. 1175 * Finally compute a suitable blkcnt. 1176 */ 1177 blksz = round_bufsz( (sndbuf_getbps(bs) * 1178 sndbuf_getspd(bs)) / chn_targetirqrate, 1179 16, CHN_2NDBUFMAXSIZE / 2); 1180 blkcnt = CHN_2NDBUFMAXSIZE / blksz; 1181 } else { /* use previously defined value */ 1182 blkcnt = sndbuf_getblkcnt(bs); 1183 blksz = sndbuf_getblksz(bs); 1184 } 1185 } else { 1186 /* 1187 * use supplied values if reasonable. Note that here we 1188 * might have blksz which is not a power of 2 if the 1189 * ioctl() to compute it allows such values. 1190 */ 1191 ret = EINVAL; 1192 if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE)) 1193 goto out; 1194 ret = 0; 1195 c->flags |= CHN_F_HAS_SIZE; 1196 } 1197 1198 reqblksz = blksz; 1199 if (reqblksz < sndbuf_getbps(bs)) 1200 reqblksz = sndbuf_getbps(bs); 1201 if (reqblksz % sndbuf_getbps(bs)) 1202 reqblksz -= reqblksz % sndbuf_getbps(bs); 1203 1204 /* adjust for different hw format/speed */ 1205 /* 1206 * Now compute the approx irq rate for the given (soft) blksz, 1207 * reduce to the acceptable range and compute a corresponding blksz 1208 * for the hard buffer. Then set the channel's blocksize and 1209 * corresponding hardbuf value. The number of blocks used should 1210 * be set by the device-specific routine. In fact, even the 1211 * call to sndbuf_setblksz() should not be here! XXX 1212 */ 1213 1214 irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / blksz; 1215 RANGE(irqhz, 16, 512); 1216 1217 maxsz = sndbuf_getmaxsize(b); 1218 if (maxsz == 0) /* virtual channels don't appear to allocate bufhard */ 1219 maxsz = CHN_2NDBUFMAXSIZE; 1220 blksz = round_bufsz( (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz, 1221 16, maxsz / 2); 1222 1223 /* Increase the size of bufsoft if before increasing bufhard. */ 1224 maxsize = sndbuf_getsize(b); 1225 if (sndbuf_getsize(bs) > maxsize) 1226 maxsize = sndbuf_getsize(bs); 1227 if (reqblksz * blkcnt > maxsize) 1228 maxsize = reqblksz * blkcnt; 1229 if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) { 1230 ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz); 1231 if (ret) 1232 goto out1; 1233 } 1234 1235 CHN_UNLOCK(c); 1236 sndbuf_setblksz(b, CHANNEL_SETBLOCKSIZE(c->methods, c->devinfo, blksz)); 1237 CHN_LOCK(c); 1238 1239 /* Decrease the size of bufsoft after decreasing bufhard. */ 1240 maxsize = sndbuf_getsize(b); 1241 if (reqblksz * blkcnt > maxsize) 1242 maxsize = reqblksz * blkcnt; 1243 if (maxsize > sndbuf_getsize(bs)) 1244 printf("Danger! %s bufsoft size increasing from %d to %d after CHANNEL_SETBLOCKSIZE()\n", 1245 c->name, sndbuf_getsize(bs), maxsize); 1246 if (sndbuf_getsize(bs) != maxsize || sndbuf_getblksz(bs) != reqblksz) { 1247 ret = sndbuf_remalloc(bs, maxsize/reqblksz, reqblksz); 1248 if (ret) 1249 goto out1; 1250 } 1251 1252 /* 1253 * OSSv4 docs: "By default OSS will set the low water level equal 1254 * to the fragment size which is optimal in most cases." 1255 */ 1256 c->lw = sndbuf_getblksz(bs); 1257 1258 chn_resetbuf(c); 1259 out1: 1260 KASSERT(sndbuf_getsize(bs) == 0 || 1261 sndbuf_getsize(bs) >= sndbuf_getsize(b), 1262 ("%s(%s): bufsoft size %d < bufhard size %d, reqblksz=%d blksz=%d maxsize=%d blkcnt=%d", 1263 __func__, c->name, sndbuf_getsize(bs), sndbuf_getsize(b), reqblksz, 1264 blksz, maxsize, blkcnt)); 1265 out: 1266 c->flags &= ~CHN_F_SETBLOCKSIZE; 1267 #if 0 1268 if (1) { 1269 static uint32_t kk = 0; 1270 printf("%u: b %d/%d/%d : (%d)%d/0x%0x | bs %d/%d/%d : (%d)%d/0x%0x\n", ++kk, 1271 sndbuf_getsize(b), sndbuf_getblksz(b), sndbuf_getblkcnt(b), 1272 sndbuf_getbps(b), 1273 sndbuf_getspd(b), sndbuf_getfmt(b), 1274 sndbuf_getsize(bs), sndbuf_getblksz(bs), sndbuf_getblkcnt(bs), 1275 sndbuf_getbps(bs), 1276 sndbuf_getspd(bs), sndbuf_getfmt(bs)); 1277 if (sndbuf_getsize(b) % sndbuf_getbps(b) || 1278 sndbuf_getblksz(b) % sndbuf_getbps(b) || 1279 sndbuf_getsize(bs) % sndbuf_getbps(bs) || 1280 sndbuf_getblksz(b) % sndbuf_getbps(b)) { 1281 printf("%u: bps/blksz alignment screwed!\n", kk); 1282 } 1283 } 1284 #endif 1285 return ret; 1286 } 1287 1288 int 1289 chn_trigger(struct pcm_channel *c, int go) 1290 { 1291 #ifdef DEV_ISA 1292 struct snd_dbuf *b = c->bufhard; 1293 #endif 1294 int ret; 1295 1296 CHN_LOCKASSERT(c); 1297 #ifdef DEV_ISA 1298 if (SND_DMA(b) && (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)) 1299 sndbuf_dmabounce(b); 1300 #endif 1301 ret = CHANNEL_TRIGGER(c->methods, c->devinfo, go); 1302 1303 return ret; 1304 } 1305 1306 /** 1307 * @brief Queries sound driver for sample-aligned hardware buffer pointer index 1308 * 1309 * This function obtains the hardware pointer location, then aligns it to 1310 * the current bytes-per-sample value before returning. (E.g., a channel 1311 * running in 16 bit stereo mode would require 4 bytes per sample, so a 1312 * hwptr value ranging from 32-35 would be returned as 32.) 1313 * 1314 * @param c PCM channel context 1315 * @returns sample-aligned hardware buffer pointer index 1316 */ 1317 int 1318 chn_getptr(struct pcm_channel *c) 1319 { 1320 #if 0 1321 int hwptr; 1322 int a = (1 << c->align) - 1; 1323 1324 CHN_LOCKASSERT(c); 1325 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; 1326 /* don't allow unaligned values in the hwa ptr */ 1327 #if 1 1328 hwptr &= ~a ; /* Apply channel align mask */ 1329 #endif 1330 hwptr &= DMA_ALIGN_MASK; /* Apply DMA align mask */ 1331 return hwptr; 1332 #endif 1333 int hwptr; 1334 1335 CHN_LOCKASSERT(c); 1336 hwptr = (c->flags & CHN_F_TRIGGERED)? CHANNEL_GETPTR(c->methods, c->devinfo) : 0; 1337 return (hwptr - (hwptr % sndbuf_getbps(c->bufhard))); 1338 } 1339 1340 struct pcmchan_caps * 1341 chn_getcaps(struct pcm_channel *c) 1342 { 1343 CHN_LOCKASSERT(c); 1344 return CHANNEL_GETCAPS(c->methods, c->devinfo); 1345 } 1346 1347 u_int32_t 1348 chn_getformats(struct pcm_channel *c) 1349 { 1350 u_int32_t *fmtlist, fmts; 1351 int i; 1352 1353 fmtlist = chn_getcaps(c)->fmtlist; 1354 fmts = 0; 1355 for (i = 0; fmtlist[i]; i++) 1356 fmts |= fmtlist[i]; 1357 1358 /* report software-supported formats */ 1359 if (report_soft_formats) 1360 fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U32_LE|AFMT_U32_BE| 1361 AFMT_S32_LE|AFMT_S32_BE|AFMT_U24_LE|AFMT_U24_BE| 1362 AFMT_S24_LE|AFMT_S24_BE|AFMT_U16_LE|AFMT_U16_BE| 1363 AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8; 1364 1365 return fmts; 1366 } 1367 1368 static int 1369 chn_buildfeeder(struct pcm_channel *c) 1370 { 1371 struct feeder_class *fc; 1372 struct pcm_feederdesc desc; 1373 u_int32_t tmp[2], type, flags, hwfmt, *fmtlist; 1374 int err; 1375 1376 CHN_LOCKASSERT(c); 1377 while (chn_removefeeder(c) == 0); 1378 KASSERT((c->feeder == NULL), ("feeder chain not empty")); 1379 1380 c->align = sndbuf_getalign(c->bufsoft); 1381 1382 if (SLIST_EMPTY(&c->children)) { 1383 fc = feeder_getclass(NULL); 1384 KASSERT(fc != NULL, ("can't find root feeder")); 1385 1386 err = chn_addfeeder(c, fc, NULL); 1387 if (err) { 1388 DEB(printf("can't add root feeder, err %d\n", err)); 1389 1390 return err; 1391 } 1392 c->feeder->desc->out = c->format; 1393 } else { 1394 if (c->flags & CHN_F_HAS_VCHAN) { 1395 desc.type = FEEDER_MIXER; 1396 desc.in = 0; 1397 } else { 1398 DEB(printf("can't decide which feeder type to use!\n")); 1399 return EOPNOTSUPP; 1400 } 1401 desc.out = c->format; 1402 desc.flags = 0; 1403 fc = feeder_getclass(&desc); 1404 if (fc == NULL) { 1405 DEB(printf("can't find vchan feeder\n")); 1406 1407 return EOPNOTSUPP; 1408 } 1409 1410 err = chn_addfeeder(c, fc, &desc); 1411 if (err) { 1412 DEB(printf("can't add vchan feeder, err %d\n", err)); 1413 1414 return err; 1415 } 1416 } 1417 c->feederflags &= ~(1 << FEEDER_VOLUME); 1418 if (c->direction == PCMDIR_PLAY && 1419 !(c->flags & CHN_F_VIRTUAL) && 1420 c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTPCMVOL) && 1421 c->parentsnddev->mixer_dev) 1422 c->feederflags |= 1 << FEEDER_VOLUME; 1423 flags = c->feederflags; 1424 fmtlist = chn_getcaps(c)->fmtlist; 1425 1426 DEB(printf("feederflags %x\n", flags)); 1427 1428 for (type = FEEDER_RATE; type <= FEEDER_LAST; type++) { 1429 if (flags & (1 << type)) { 1430 desc.type = type; 1431 desc.in = 0; 1432 desc.out = 0; 1433 desc.flags = 0; 1434 DEB(printf("find feeder type %d, ", type)); 1435 fc = feeder_getclass(&desc); 1436 DEB(printf("got %p\n", fc)); 1437 if (fc == NULL) { 1438 DEB(printf("can't find required feeder type %d\n", type)); 1439 1440 return EOPNOTSUPP; 1441 } 1442 1443 DEB(printf("build fmtchain from 0x%08x to 0x%08x: ", c->feeder->desc->out, fc->desc->in)); 1444 tmp[0] = fc->desc->in; 1445 tmp[1] = 0; 1446 if (chn_fmtchain(c, tmp) == 0) { 1447 DEB(printf("failed\n")); 1448 1449 return ENODEV; 1450 } 1451 DEB(printf("ok\n")); 1452 1453 err = chn_addfeeder(c, fc, fc->desc); 1454 if (err) { 1455 DEB(printf("can't add feeder %p, output 0x%x, err %d\n", fc, fc->desc->out, err)); 1456 1457 return err; 1458 } 1459 DEB(printf("added feeder %p, output 0x%x\n", fc, c->feeder->desc->out)); 1460 } 1461 } 1462 1463 if (c->direction == PCMDIR_REC) { 1464 tmp[0] = c->format; 1465 tmp[1] = 0; 1466 hwfmt = chn_fmtchain(c, tmp); 1467 } else 1468 hwfmt = chn_fmtchain(c, fmtlist); 1469 1470 if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) { 1471 DEB(printf("Invalid hardware format: 0x%08x\n", hwfmt)); 1472 return ENODEV; 1473 } 1474 1475 sndbuf_setfmt(c->bufhard, hwfmt); 1476 1477 if ((flags & (1 << FEEDER_VOLUME))) { 1478 uint32_t parent = SOUND_MIXER_NONE; 1479 int vol, left, right; 1480 1481 vol = 100 | (100 << 8); 1482 1483 CHN_UNLOCK(c); 1484 /* 1485 * XXX This is ugly! The way mixer subs being so secretive 1486 * about its own internals force us to use this silly 1487 * monkey trick. 1488 */ 1489 if (mixer_ioctl(c->parentsnddev->mixer_dev, 1490 MIXER_READ(SOUND_MIXER_PCM), (caddr_t)&vol, -1, NULL) != 0) 1491 device_printf(c->dev, "Soft PCM Volume: Failed to read default value\n"); 1492 left = vol & 0x7f; 1493 right = (vol >> 8) & 0x7f; 1494 if (c->parentsnddev != NULL && 1495 c->parentsnddev->mixer_dev != NULL && 1496 c->parentsnddev->mixer_dev->si_drv1 != NULL) 1497 parent = mix_getparent( 1498 c->parentsnddev->mixer_dev->si_drv1, 1499 SOUND_MIXER_PCM); 1500 if (parent != SOUND_MIXER_NONE) { 1501 vol = 100 | (100 << 8); 1502 if (mixer_ioctl(c->parentsnddev->mixer_dev, 1503 MIXER_READ(parent), 1504 (caddr_t)&vol, -1, NULL) != 0) 1505 device_printf(c->dev, "Soft Volume: Failed to read parent default value\n"); 1506 left = (left * (vol & 0x7f)) / 100; 1507 right = (right * ((vol >> 8) & 0x7f)) / 100; 1508 } 1509 CHN_LOCK(c); 1510 chn_setvolume(c, left, right); 1511 } 1512 1513 return 0; 1514 } 1515 1516 int 1517 chn_notify(struct pcm_channel *c, u_int32_t flags) 1518 { 1519 struct pcmchan_children *pce; 1520 struct pcm_channel *child; 1521 int run; 1522 1523 CHN_LOCK(c); 1524 1525 if (SLIST_EMPTY(&c->children)) { 1526 CHN_UNLOCK(c); 1527 return ENODEV; 1528 } 1529 1530 run = (c->flags & CHN_F_TRIGGERED)? 1 : 0; 1531 /* 1532 * if the hwchan is running, we can't change its rate, format or 1533 * blocksize 1534 */ 1535 if (run) 1536 flags &= CHN_N_VOLUME | CHN_N_TRIGGER; 1537 1538 if (flags & CHN_N_RATE) { 1539 /* 1540 * we could do something here, like scan children and decide on 1541 * the most appropriate rate to mix at, but we don't for now 1542 */ 1543 } 1544 if (flags & CHN_N_FORMAT) { 1545 /* 1546 * we could do something here, like scan children and decide on 1547 * the most appropriate mixer feeder to use, but we don't for now 1548 */ 1549 } 1550 if (flags & CHN_N_VOLUME) { 1551 /* 1552 * we could do something here but we don't for now 1553 */ 1554 } 1555 if (flags & CHN_N_BLOCKSIZE) { 1556 int blksz; 1557 /* 1558 * scan the children, find the lowest blocksize and use that 1559 * for the hard blocksize 1560 */ 1561 blksz = sndbuf_getmaxsize(c->bufhard) / 2; 1562 SLIST_FOREACH(pce, &c->children, link) { 1563 child = pce->channel; 1564 CHN_LOCK(child); 1565 if (sndbuf_getblksz(child->bufhard) < blksz) 1566 blksz = sndbuf_getblksz(child->bufhard); 1567 CHN_UNLOCK(child); 1568 } 1569 chn_setblocksize(c, 2, blksz); 1570 } 1571 if (flags & CHN_N_TRIGGER) { 1572 int nrun; 1573 /* 1574 * scan the children, and figure out if any are running 1575 * if so, we need to be running, otherwise we need to be stopped 1576 * if we aren't in our target sstate, move to it 1577 */ 1578 nrun = 0; 1579 SLIST_FOREACH(pce, &c->children, link) { 1580 child = pce->channel; 1581 CHN_LOCK(child); 1582 if (child->flags & CHN_F_TRIGGERED) 1583 nrun = 1; 1584 CHN_UNLOCK(child); 1585 } 1586 if (nrun && !run) 1587 chn_start(c, 1); 1588 if (!nrun && run) 1589 chn_abort(c); 1590 } 1591 CHN_UNLOCK(c); 1592 return 0; 1593 } 1594 1595 /** 1596 * @brief Fetch array of supported discrete sample rates 1597 * 1598 * Wrapper for CHANNEL_GETRATES. Please see channel_if.m:getrates() for 1599 * detailed information. 1600 * 1601 * @note If the operation isn't supported, this function will just return 0 1602 * (no rates in the array), and *rates will be set to NULL. Callers 1603 * should examine rates @b only if this function returns non-zero. 1604 * 1605 * @param c pcm channel to examine 1606 * @param rates pointer to array of integers; rate table will be recorded here 1607 * 1608 * @return number of rates in the array pointed to be @c rates 1609 */ 1610 int 1611 chn_getrates(struct pcm_channel *c, int **rates) 1612 { 1613 KASSERT(rates != NULL, ("rates is null")); 1614 CHN_LOCKASSERT(c); 1615 return CHANNEL_GETRATES(c->methods, c->devinfo, rates); 1616 } 1617 1618 /** 1619 * @brief Remove channel from a sync group, if there is one. 1620 * 1621 * This function is initially intended for the following conditions: 1622 * - Starting a syncgroup (@c SNDCTL_DSP_SYNCSTART ioctl) 1623 * - Closing a device. (A channel can't be destroyed if it's still in use.) 1624 * 1625 * @note Before calling this function, the syncgroup list mutex must be 1626 * held. (Consider pcm_channel::sm protected by the SG list mutex 1627 * whether @c c is locked or not.) 1628 * 1629 * @param c channel device to be started or closed 1630 * @returns If this channel was the only member of a group, the group ID 1631 * is returned to the caller so that the caller can release it 1632 * via free_unr() after giving up the syncgroup lock. Else it 1633 * returns 0. 1634 */ 1635 int 1636 chn_syncdestroy(struct pcm_channel *c) 1637 { 1638 struct pcmchan_syncmember *sm; 1639 struct pcmchan_syncgroup *sg; 1640 int sg_id; 1641 1642 sg_id = 0; 1643 1644 PCM_SG_LOCKASSERT(MA_OWNED); 1645 1646 if (c->sm != NULL) { 1647 sm = c->sm; 1648 sg = sm->parent; 1649 c->sm = NULL; 1650 1651 KASSERT(sg != NULL, ("syncmember has null parent")); 1652 1653 SLIST_REMOVE(&sg->members, sm, pcmchan_syncmember, link); 1654 free(sm, M_DEVBUF); 1655 1656 if (SLIST_EMPTY(&sg->members)) { 1657 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link); 1658 sg_id = sg->id; 1659 free(sg, M_DEVBUF); 1660 } 1661 } 1662 1663 return sg_id; 1664 } 1665 1666 void 1667 chn_lock(struct pcm_channel *c) 1668 { 1669 CHN_LOCK(c); 1670 } 1671 1672 void 1673 chn_unlock(struct pcm_channel *c) 1674 { 1675 CHN_UNLOCK(c); 1676 } 1677 1678 #ifdef OSSV4_EXPERIMENT 1679 int 1680 chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak) 1681 { 1682 CHN_LOCKASSERT(c); 1683 return CHANNEL_GETPEAKS(c->methods, c->devinfo, lpeak, rpeak); 1684 } 1685 #endif 1686