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