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